async def send_video_note( self, chat_id: Union[int, str], video_note: str, duration: int = 0, length: int = 1, thumb: str = None, disable_notification: bool = None, reply_to_message_id: int = None, reply_markup: Union["pyrogram.InlineKeyboardMarkup", "pyrogram.ReplyKeyboardMarkup", "pyrogram.ReplyKeyboardRemove", "pyrogram.ForceReply"] = None, progress: callable = None, progress_args: tuple = () ) -> Union["pyrogram.Message", None]: """Use this method to send video messages. Args: chat_id (``int`` | ``str``): Unique identifier (int) or username (str) of the target chat. For your personal cloud (Saved Messages) you can simply use "me" or "self". For a contact that exists in your Telegram address book you can use his phone number (str). video_note (``str``): Video note to send. Pass a file_id as string to send a video note that exists on the Telegram servers, or pass a file path as string to upload a new video note that exists on your local machine. Sending video notes by a URL is currently unsupported. duration (``int``, *optional*): Duration of sent video in seconds. length (``int``, *optional*): Video width and height. thumb (``str``, *optional*): Thumbnail of the video sent. The thumbnail should be in JPEG format and less than 200 KB in size. A thumbnail's width and height should not exceed 90 pixels. Thumbnails can't be reused and can be only uploaded as a new file. disable_notification (``bool``, *optional*): Sends the message silently. Users will receive a notification with no sound. reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. progress (``callable``, *optional*): Pass a callback function to view the upload progress. The function must take *(client, current, total, \*args)* as positional arguments (look at the section below for a detailed description). progress_args (``tuple``, *optional*): Extra custom arguments for the progress callback function. Useful, for example, if you want to pass a chat_id and a message_id in order to edit a message with the updated progress. Other Parameters: client (:obj:`Client <pyrogram.Client>`): The Client itself, useful when you want to call other API methods inside the callback function. current (``int``): The amount of bytes uploaded so far. total (``int``): The size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. You can either keep *\*args* or add every single extra argument in your function signature. Returns: On success, the sent :obj:`Message <pyrogram.Message>` is returned. In case the upload is deliberately stopped with :meth:`stop_transmission`, None is returned instead. Raises: :class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error. """ file = None try: if os.path.exists(video_note): thumb = None if thumb is None else await self.save_file(thumb) file = await self.save_file(video_note, progress=progress, progress_args=progress_args) media = types.InputMediaUploadedDocument( mime_type="video/mp4", file=file, thumb=thumb, attributes=[ types.DocumentAttributeVideo(round_message=True, duration=duration, w=length, h=length) ]) else: try: decoded = utils.decode(video_note) fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq" unpacked = struct.unpack(fmt, decoded) except (AssertionError, binascii.Error, struct.error): raise FileIdInvalid from None else: if unpacked[0] != 13: media_type = BaseClient.MEDIA_TYPE_ID.get( unpacked[0], None) if media_type: raise FileIdInvalid( "The file_id belongs to a {}".format( media_type)) else: raise FileIdInvalid( "Unknown media type: {}".format(unpacked[0])) media = types.InputMediaDocument( id=types.InputDocument(id=unpacked[2], access_hash=unpacked[3], file_reference=b"")) while True: try: r = await self.send( functions.messages.SendMedia( peer=await self.resolve_peer(chat_id), media=media, silent=disable_notification or None, reply_to_msg_id=reply_to_message_id, random_id=self.rnd_id(), reply_markup=reply_markup.write() if reply_markup else None, message="")) except FilePartMissing as e: await self.save_file(video_note, file_id=file.id, file_part=e.x) else: for i in r.updates: if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)): return await pyrogram.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}) except BaseClient.StopTransmission: return None
def send_animation( self, chat_id: Union[int, str], animation: str, caption: str = "", unsave: bool = False, parse_mode: str = "", duration: int = 0, width: int = 0, height: int = 0, thumb: str = None, disable_notification: bool = None, reply_to_message_id: int = None, reply_markup: Union["pyrogram.InlineKeyboardMarkup", "pyrogram.ReplyKeyboardMarkup", "pyrogram.ReplyKeyboardRemove", "pyrogram.ForceReply"] = None, progress: callable = None, progress_args: tuple = () ) -> Union["pyrogram.Message", None]: """Send animation files (animation or H.264/MPEG-4 AVC video without sound). Parameters: chat_id (``int`` | ``str``): Unique identifier (int) or username (str) of the target chat. For your personal cloud (Saved Messages) you can simply use "me" or "self". For a contact that exists in your Telegram address book you can use his phone number (str). animation (``str``): Animation to send. Pass a file_id as string to send an animation that exists on the Telegram servers, pass an HTTP URL as a string for Telegram to get an animation from the Internet, or pass a file path as string to upload a new animation that exists on your local machine. caption (``str``, *optional*): Animation caption, 0-1024 characters. unsave (``bool``, *optional*): By default, the server will save into your own collection any new animation GIF you send. Pass True to automatically unsave the sent animation. Defaults to False. parse_mode (``str``, *optional*): Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your caption. Defaults to "markdown". duration (``int``, *optional*): Duration of sent animation in seconds. width (``int``, *optional*): Animation width. height (``int``, *optional*): Animation height. thumb (``str``, *optional*): Thumbnail of the animation file sent. The thumbnail should be in JPEG format and less than 200 KB in size. A thumbnail's width and height should not exceed 320 pixels. Thumbnails can't be reused and can be only uploaded as a new file. disable_notification (``bool``, *optional*): Sends the message silently. Users will receive a notification with no sound. reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message. reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. progress (``callable``, *optional*): Pass a callback function to view the upload progress. The function must take *(client, current, total, \*args)* as positional arguments (look at the section below for a detailed description). progress_args (``tuple``, *optional*): Extra custom arguments for the progress callback function. Useful, for example, if you want to pass a chat_id and a message_id in order to edit a message with the updated progress. Other Parameters: client (:obj:`Client`): The Client itself, useful when you want to call other API methods inside the callback function. current (``int``): The amount of bytes uploaded so far. total (``int``): The size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. You can either keep *\*args* or add every single extra argument in your function signature. Returns: :obj:`Message` | ``None``: On success, the sent animation message is returned, otherwise, in case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. Raises: RPCError: In case of a Telegram RPC error. """ file = None style = self.html if parse_mode.lower() == "html" else self.markdown try: if os.path.exists(animation): thumb = None if thumb is None else self.save_file(thumb) file = self.save_file(animation, progress=progress, progress_args=progress_args) media = types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(animation) or "video/mp4", file=file, thumb=thumb, attributes=[ types.DocumentAttributeVideo(supports_streaming=True, duration=duration, w=width, h=height), types.DocumentAttributeFilename( file_name=os.path.basename(animation)), types.DocumentAttributeAnimated() ]) elif animation.startswith("http"): media = types.InputMediaDocumentExternal(url=animation) else: media = utils.get_input_media_from_file_id(animation, 10) while True: try: r = self.send( functions.messages.SendMedia( peer=self.resolve_peer(chat_id), media=media, silent=disable_notification or None, reply_to_msg_id=reply_to_message_id, random_id=self.rnd_id(), reply_markup=reply_markup.write() if reply_markup else None, **style.parse(caption))) except FilePartMissing as e: self.save_file(animation, file_id=file.id, file_part=e.x) else: for i in r.updates: if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)): message = pyrogram.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}) if unsave: document = message.animation or message.document document_id = utils.get_input_media_from_file_id( document.file_id).id self.send( functions.messages.SaveGif(id=document_id, unsave=True)) return message except BaseClient.StopTransmission: return None
async def send_sticker( chat_id: Union[int, str], sticker: str, file_ref: str = None, disable_notification: bool = None, reply_to_message_id: int = None, schedule_date: int = None, reply_markup: Union["pyrogram.InlineKeyboardMarkup", "pyrogram.ReplyKeyboardMarkup", "pyrogram.ReplyKeyboardRemove", "pyrogram.ForceReply"] = None, progress: callable = None, progress_args: tuple = () ) -> Union["pyrogram.Message", None]: if True: file = None try: if os.path.exists(sticker): file = await app.save_file(sticker, progress=progress, progress_args=progress_args) media = types.InputMediaUploadedDocument( mime_type="image/webp", file=file, attributes=[ types.DocumentAttributeFilename( file_name=os.path.basename(sticker)) ]) elif sticker.startswith("http"): media = types.InputMediaDocumentExternal(url=sticker) else: media = utils.get_input_media_from_file_id( sticker, file_ref, 8) while True: try: r = await app.send( functions.messages.SendMedia( peer=await app.resolve_peer(chat_id), media=media, silent=disable_notification or None, reply_to_msg_id=reply_to_message_id, random_id=app.rnd_id(), schedule_date=schedule_date, reply_markup=reply_markup.write() if reply_markup else None, message="")) except FilePartMissing as e: await app.save_file(sticker, file_id=file.id, file_part=e.x) else: for i in r.updates: if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage, types.UpdateNewScheduledMessage)): return await pyrogram.Message._parse( app, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, is_scheduled=isinstance( i, types.UpdateNewScheduledMessage)) except BaseClient.StopTransmission: return None app.send( functions.channels.DeleteUserHistory(app.resolve_peer(chat.id), app.resolve_peer(user_id)))
def send_media_group(self, chat_id: Union[int, str], media: List[Union["pyrogram.InputMediaPhoto", "pyrogram.InputMediaVideo"]], disable_notification: bool = None, reply_to_message_id: int = None): """Use this method to send a group of photos or videos as an album. Args: chat_id (``int`` | ``str``): Unique identifier (int) or username (str) of the target chat. For your personal cloud (Saved Messages) you can simply use "me" or "self". For a contact that exists in your Telegram address book you can use his phone number (str). media (List of :obj:`InputMediaPhoto` and :obj:`InputMediaVideo`): A list describing photos and videos to be sent, must include 2–10 items. disable_notification (``bool``, *optional*): Sends the message silently. Users will receive a notification with no sound. reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message. Returns: On success, a :obj:`Messages <pyrogram.Messages>` object is returned containing all the single messages sent. Raises: :class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error. """ multi_media = [] for i in media: style = self.html if i.parse_mode.lower( ) == "html" else self.markdown if isinstance(i, pyrogram.InputMediaPhoto): if os.path.exists(i.media): while True: try: media = self.send( functions.messages.UploadMedia( peer=self.resolve_peer(chat_id), media=types.InputMediaUploadedPhoto( file=self.save_file(i.media)))) except FloodWait as e: log.warning("Sleeping for {}s".format(e.x)) time.sleep(e.x) else: break media = types.InputMediaPhoto(id=types.InputPhoto( id=media.photo.id, access_hash=media.photo.access_hash, file_reference=b"")) else: try: decoded = utils.decode(i.media) fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq" unpacked = struct.unpack(fmt, decoded) except (AssertionError, binascii.Error, struct.error): raise FileIdInvalid from None else: if unpacked[0] != 2: media_type = BaseClient.MEDIA_TYPE_ID.get( unpacked[0], None) if media_type: raise FileIdInvalid( "The file_id belongs to a {}".format( media_type)) else: raise FileIdInvalid( "Unknown media type: {}".format( unpacked[0])) media = types.InputMediaPhoto( id=types.InputPhoto(id=unpacked[2], access_hash=unpacked[3], file_reference=b"")) elif isinstance(i, pyrogram.InputMediaVideo): if os.path.exists(i.media): while True: try: media = self.send( functions.messages.UploadMedia( peer=self.resolve_peer(chat_id), media=types.InputMediaUploadedDocument( file=self.save_file(i.media), thumb=None if i.thumb is None else self.save_file(i.thumb), mime_type="video/mp4", attributes=[ types.DocumentAttributeVideo( supports_streaming=i. supports_streaming or None, duration=i.duration, w=i.width, h=i.height), types.DocumentAttributeFilename( file_name=os.path.basename( i.media)) ]))) except FloodWait as e: log.warning("Sleeping for {}s".format(e.x)) time.sleep(e.x) else: break media = types.InputMediaDocument(id=types.InputDocument( id=media.document.id, access_hash=media.document.access_hash, file_reference=b"")) else: try: decoded = utils.decode(i.media) fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq" unpacked = struct.unpack(fmt, decoded) except (AssertionError, binascii.Error, struct.error): raise FileIdInvalid from None else: if unpacked[0] != 4: media_type = BaseClient.MEDIA_TYPE_ID.get( unpacked[0], None) if media_type: raise FileIdInvalid( "The file_id belongs to a {}".format( media_type)) else: raise FileIdInvalid( "Unknown media type: {}".format( unpacked[0])) media = types.InputMediaDocument( id=types.InputDocument(id=unpacked[2], access_hash=unpacked[3], file_reference=b"")) multi_media.append( types.InputSingleMedia(media=media, random_id=self.rnd_id(), **style.parse(i.caption))) while True: try: r = self.send( functions.messages.SendMultiMedia( peer=self.resolve_peer(chat_id), multi_media=multi_media, silent=disable_notification or None, reply_to_msg_id=reply_to_message_id)) except FloodWait as e: log.warning("Sleeping for {}s".format(e.x)) time.sleep(e.x) else: break return pyrogram.Messages._parse( self, types.messages.Messages(messages=[ m.message for m in filter( lambda u: isinstance(u, (types.UpdateNewMessage, types. UpdateNewChannelMessage)), r.updates) ], users=r.users, chats=r.chats))
def send_media_group( self, chat_id: Union[int, str], media: List[Union["pyrogram.InputMediaPhoto", "pyrogram.InputMediaVideo"]], disable_notification: bool = None, reply_to_message_id: int = None) -> List["pyrogram.Message"]: """Send a group of photos or videos as an album. Parameters: chat_id (``int`` | ``str``): Unique identifier (int) or username (str) of the target chat. For your personal cloud (Saved Messages) you can simply use "me" or "self". For a contact that exists in your Telegram address book you can use his phone number (str). media (List of :obj:`InputMediaPhoto` and :obj:`InputMediaVideo`): A list describing photos and videos to be sent, must include 2–10 items. disable_notification (``bool``, *optional*): Sends the message silently. Users will receive a notification with no sound. reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message. Returns: List of :obj:`Message`: On success, a list of the sent messages is returned. Example: .. code-block:: python from pyrogram import InputMediaPhoto, InputMediaVideo app.send_media_group( "me", [ InputMediaPhoto("photo1.jpg"), InputMediaPhoto("photo2.jpg", caption="photo caption"), InputMediaVideo("video.mp4", caption="a video") ] ) """ multi_media = [] for i in media: if isinstance(i, pyrogram.InputMediaPhoto): if os.path.exists(i.media): while True: try: media = self.send( functions.messages.UploadMedia( peer=self.resolve_peer(chat_id), media=types.InputMediaUploadedPhoto( file=self.save_file(i.media)))) except FloodWait as e: log.warning("Sleeping for {}s".format(e.x)) time.sleep(e.x) else: break media = types.InputMediaPhoto(id=types.InputPhoto( id=media.photo.id, access_hash=media.photo.access_hash, file_reference=media.photo.file_reference)) elif i.media.startswith("http"): media = self.send( functions.messages.UploadMedia( peer=self.resolve_peer(chat_id), media=types.InputMediaPhotoExternal(url=i.media))) media = types.InputMediaPhoto(id=types.InputPhoto( id=media.photo.id, access_hash=media.photo.access_hash, file_reference=media.photo.file_reference)) else: media = utils.get_input_media_from_file_id( i.media, i.file_ref, 2) elif isinstance(i, pyrogram.InputMediaVideo): if os.path.exists(i.media): while True: try: media = self.send( functions.messages.UploadMedia( peer=self.resolve_peer(chat_id), media=types.InputMediaUploadedDocument( file=self.save_file(i.media), thumb=None if i.thumb is None else self.save_file(i.thumb), mime_type=self.guess_mime_type(i.media) or "video/mp4", attributes=[ types.DocumentAttributeVideo( supports_streaming=i. supports_streaming or None, duration=i.duration, w=i.width, h=i.height), types.DocumentAttributeFilename( file_name=os.path.basename( i.media)) ]))) except FloodWait as e: log.warning("Sleeping for {}s".format(e.x)) time.sleep(e.x) else: break media = types.InputMediaDocument(id=types.InputDocument( id=media.document.id, access_hash=media.document.access_hash, file_reference=media.document.file_reference)) elif i.media.startswith("http"): media = self.send( functions.messages.UploadMedia( peer=self.resolve_peer(chat_id), media=types.InputMediaDocumentExternal( url=i.media))) media = types.InputMediaDocument(id=types.InputDocument( id=media.document.id, access_hash=media.document.access_hash, file_reference=media.document.file_reference)) else: media = utils.get_input_media_from_file_id( i.media, i.file_ref, 4) multi_media.append( types.InputSingleMedia(media=media, random_id=self.rnd_id(), **self.parser.parse( i.caption, i.parse_mode))) while True: try: r = self.send( functions.messages.SendMultiMedia( peer=self.resolve_peer(chat_id), multi_media=multi_media, silent=disable_notification or None, reply_to_msg_id=reply_to_message_id)) except FloodWait as e: log.warning("Sleeping for {}s".format(e.x)) time.sleep(e.x) else: break return utils.parse_messages( self, types.messages.Messages(messages=[ m.message for m in filter( lambda u: isinstance(u, (types.UpdateNewMessage, types. UpdateNewChannelMessage)), r.updates) ], users=r.users, chats=r.chats))
def send_sticker(self, chat_id: int or str, sticker: str, disable_notification: bool = None, reply_to_message_id: int = None, reply_markup=None, progress: callable = None, progress_args: tuple = ()): """Use this method to send .webp stickers. Args: chat_id (``int`` | ``str``): Unique identifier (int) or username (str) of the target chat. For your personal cloud (Saved Messages) you can simply use "me" or "self". For a contact that exists in your Telegram address book you can use his phone number (str). For a private channel/supergroup you can use its *t.me/joinchat/* link. sticker (``str``): Sticker to send. Pass a file_id as string to send a sticker that exists on the Telegram servers, pass an HTTP URL as a string for Telegram to get a .webp sticker file from the Internet, or pass a file path as string to upload a new sticker that exists on your local machine. disable_notification (``bool``, *optional*): Sends the message silently. Users will receive a notification with no sound. reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message. reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. progress (``callable``, *optional*): Pass a callback function to view the upload progress. The function must take *(client, current, total, \*args)* as positional arguments (look at the section below for a detailed description). progress_args (``tuple``, *optional*): Extra custom arguments for the progress callback function. Useful, for example, if you want to pass a chat_id and a message_id in order to edit a message with the updated progress. Other Parameters: client (:obj:`Client <pyrogram.Client>`): The Client itself, useful when you want to call other API methods inside the callback function. current (``int``): The amount of bytes uploaded so far. total (``int``): The size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. You can either keep *\*args* or add every single extra argument in your function signature. Returns: On success, the sent :obj:`Message <pyrogram.Message>` is returned. Raises: :class:`Error <pyrogram.Error>` """ file = None if os.path.exists(sticker): file = self.save_file(sticker, progress=progress, progress_args=progress_args) media = types.InputMediaUploadedDocument( mime_type="image/webp", file=file, attributes=[ types.DocumentAttributeFilename(os.path.basename(sticker)) ]) elif sticker.startswith("http"): media = types.InputMediaDocumentExternal(url=sticker) else: try: decoded = utils.decode(sticker) fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq" unpacked = struct.unpack(fmt, decoded) except (AssertionError, binascii.Error, struct.error): raise FileIdInvalid from None else: if unpacked[0] != 8: media_type = BaseClient.MEDIA_TYPE_ID.get( unpacked[0], None) if media_type: raise FileIdInvalid( "The file_id belongs to a {}".format(media_type)) else: raise FileIdInvalid("Unknown media type: {}".format( unpacked[0])) media = types.InputMediaDocument(id=types.InputDocument( id=unpacked[2], access_hash=unpacked[3])) while True: try: r = self.send( functions.messages.SendMedia( peer=self.resolve_peer(chat_id), media=media, silent=disable_notification or None, reply_to_msg_id=reply_to_message_id, random_id=self.rnd_id(), reply_markup=reply_markup.write() if reply_markup else None, message="")) except FilePartMissing as e: self.save_file(sticker, file_id=file.id, file_part=e.x) else: for i in r.updates: if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)): return utils.parse_messages(self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats})
async def edit_message_media( self, chat_id: Union[int, str], message_id: int, media: InputMedia, reply_markup: "pyrogram.InlineKeyboardMarkup" = None ) -> "pyrogram.Message": """Use this method to edit audio, document, photo, or video messages. If a message is a part of a message album, then it can be edited only to a photo or a video. Otherwise, message type can be changed arbitrarily. When inline message is edited, new file can't be uploaded. Use previously uploaded file via its file_id or specify a URL. On success, if the edited message was sent by the bot, the edited Message is returned, otherwise True is returned. Args: chat_id (``int`` | ``str``): Unique identifier (int) or username (str) of the target chat. For your personal cloud (Saved Messages) you can simply use "me" or "self". For a contact that exists in your Telegram address book you can use his phone number (str). message_id (``int``): Message identifier in the chat specified in chat_id. media (:obj:`InputMedia`) One of the InputMedia objects describing an animation, audio, document, photo or video. reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): An InlineKeyboardMarkup object. Returns: On success, the edited :obj:`Message <pyrogram.Message>` is returned. Raises: :class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error. """ style = self.html if media.parse_mode.lower( ) == "html" else self.markdown caption = media.caption if isinstance(media, InputMediaPhoto): if os.path.exists(media.media): media = await self.send( functions.messages.UploadMedia( peer=await self.resolve_peer(chat_id), media=types.InputMediaUploadedPhoto( file=await self.save_file(media.media)))) media = types.InputMediaPhoto( id=types.InputPhoto(id=media.photo.id, access_hash=media.photo.access_hash, file_reference=b"")) elif media.media.startswith("http"): media = types.InputMediaPhotoExternal(url=media.media) else: try: decoded = utils.decode(media.media) fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq" unpacked = struct.unpack(fmt, decoded) except (AssertionError, binascii.Error, struct.error): raise FileIdInvalid from None else: if unpacked[0] != 2: media_type = BaseClient.MEDIA_TYPE_ID.get( unpacked[0], None) if media_type: raise FileIdInvalid( "The file_id belongs to a {}".format( media_type)) else: raise FileIdInvalid( "Unknown media type: {}".format(unpacked[0])) media = types.InputMediaPhoto( id=types.InputPhoto(id=unpacked[2], access_hash=unpacked[3], file_reference=b"")) if isinstance(media, InputMediaVideo): if os.path.exists(media.media): media = await self.send( functions.messages.UploadMedia( peer=await self.resolve_peer(chat_id), media=types.InputMediaUploadedDocument( mime_type="video/mp4", thumb=None if media.thumb is None else self.save_file(media.thumb), file=await self.save_file(media.media), attributes=[ types.DocumentAttributeVideo( supports_streaming=media.supports_streaming or None, duration=media.duration, w=media.width, h=media.height), types.DocumentAttributeFilename( file_name=os.path.basename(media.media)) ]))) media = types.InputMediaDocument(id=types.InputDocument( id=media.document.id, access_hash=media.document.access_hash, file_reference=b"")) elif media.media.startswith("http"): media = types.InputMediaDocumentExternal(url=media.media) else: try: decoded = utils.decode(media.media) fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq" unpacked = struct.unpack(fmt, decoded) except (AssertionError, binascii.Error, struct.error): raise FileIdInvalid from None else: if unpacked[0] != 4: media_type = BaseClient.MEDIA_TYPE_ID.get( unpacked[0], None) if media_type: raise FileIdInvalid( "The file_id belongs to a {}".format( media_type)) else: raise FileIdInvalid( "Unknown media type: {}".format(unpacked[0])) media = types.InputMediaDocument( id=types.InputDocument(id=unpacked[2], access_hash=unpacked[3], file_reference=b"")) if isinstance(media, InputMediaAudio): if os.path.exists(media.media): media = await self.send( functions.messages.UploadMedia( peer=await self.resolve_peer(chat_id), media=types.InputMediaUploadedDocument( mime_type="audio/mpeg", thumb=None if media.thumb is None else self.save_file(media.thumb), file=await self.save_file(media.media), attributes=[ types.DocumentAttributeAudio( duration=media.duration, performer=media.performer, title=media.title), types.DocumentAttributeFilename( file_name=os.path.basename(media.media)) ]))) media = types.InputMediaDocument(id=types.InputDocument( id=media.document.id, access_hash=media.document.access_hash, file_reference=b"")) elif media.media.startswith("http"): media = types.InputMediaDocumentExternal(url=media.media) else: try: decoded = utils.decode(media.media) fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq" unpacked = struct.unpack(fmt, decoded) except (AssertionError, binascii.Error, struct.error): raise FileIdInvalid from None else: if unpacked[0] != 9: media_type = BaseClient.MEDIA_TYPE_ID.get( unpacked[0], None) if media_type: raise FileIdInvalid( "The file_id belongs to a {}".format( media_type)) else: raise FileIdInvalid( "Unknown media type: {}".format(unpacked[0])) media = types.InputMediaDocument( id=types.InputDocument(id=unpacked[2], access_hash=unpacked[3], file_reference=b"")) if isinstance(media, InputMediaAnimation): if os.path.exists(media.media): media = await self.send( functions.messages.UploadMedia( peer=await self.resolve_peer(chat_id), media=types.InputMediaUploadedDocument( mime_type="video/mp4", thumb=None if media.thumb is None else self.save_file(media.thumb), file=await self.save_file(media.media), attributes=[ types.DocumentAttributeVideo( supports_streaming=True, duration=media.duration, w=media.width, h=media.height), types.DocumentAttributeFilename( file_name=os.path.basename(media.media)), types.DocumentAttributeAnimated() ]))) media = types.InputMediaDocument(id=types.InputDocument( id=media.document.id, access_hash=media.document.access_hash, file_reference=b"")) elif media.media.startswith("http"): media = types.InputMediaDocumentExternal(url=media.media) else: try: decoded = utils.decode(media.media) fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq" unpacked = struct.unpack(fmt, decoded) except (AssertionError, binascii.Error, struct.error): raise FileIdInvalid from None else: if unpacked[0] != 10: media_type = BaseClient.MEDIA_TYPE_ID.get( unpacked[0], None) if media_type: raise FileIdInvalid( "The file_id belongs to a {}".format( media_type)) else: raise FileIdInvalid( "Unknown media type: {}".format(unpacked[0])) media = types.InputMediaDocument( id=types.InputDocument(id=unpacked[2], access_hash=unpacked[3], file_reference=b"")) if isinstance(media, InputMediaDocument): if os.path.exists(media.media): media = await self.send( functions.messages.UploadMedia( peer=await self.resolve_peer(chat_id), media=types.InputMediaUploadedDocument( mime_type="application/zip", thumb=None if media.thumb is None else self.save_file(media.thumb), file=await self.save_file(media.media), attributes=[ types.DocumentAttributeFilename( file_name=os.path.basename(media.media)) ]))) media = types.InputMediaDocument(id=types.InputDocument( id=media.document.id, access_hash=media.document.access_hash, file_reference=b"")) elif media.media.startswith("http"): media = types.InputMediaDocumentExternal(url=media.media) else: try: decoded = utils.decode(media.media) fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq" unpacked = struct.unpack(fmt, decoded) except (AssertionError, binascii.Error, struct.error): raise FileIdInvalid from None else: if unpacked[0] not in (5, 10): media_type = BaseClient.MEDIA_TYPE_ID.get( unpacked[0], None) if media_type: raise FileIdInvalid( "The file_id belongs to a {}".format( media_type)) else: raise FileIdInvalid( "Unknown media type: {}".format(unpacked[0])) media = types.InputMediaDocument( id=types.InputDocument(id=unpacked[2], access_hash=unpacked[3], file_reference=b"")) r = await self.send( functions.messages.EditMessage( peer=await self.resolve_peer(chat_id), id=message_id, reply_markup=reply_markup.write() if reply_markup else None, media=media, **await style.parse(caption))) for i in r.updates: if isinstance( i, (types.UpdateEditMessage, types.UpdateEditChannelMessage)): return await pyrogram.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats})
async def send_audio( self, chat_id: Union[int, str], audio: str, caption: str = "", parse_mode: Union[str, None] = "", duration: int = 0, performer: str = None, title: str = None, thumb: str = None, disable_notification: bool = None, reply_to_message_id: int = None, reply_markup: Union[ "pyrogram.InlineKeyboardMarkup", "pyrogram.ReplyKeyboardMarkup", "pyrogram.ReplyKeyboardRemove", "pyrogram.ForceReply" ] = None, progress: callable = None, progress_args: tuple = () ) -> Union["pyrogram.Message", None]: """Send audio files. For sending voice messages, use the :obj:`send_voice()` method instead. Parameters: chat_id (``int`` | ``str``): Unique identifier (int) or username (str) of the target chat. For your personal cloud (Saved Messages) you can simply use "me" or "self". For a contact that exists in your Telegram address book you can use his phone number (str). audio (``str``): Audio file to send. Pass a file_id as string to send an audio file that exists on the Telegram servers, pass an HTTP URL as a string for Telegram to get an audio file from the Internet, or pass a file path as string to upload a new audio file that exists on your local machine. caption (``str``, *optional*): Audio caption, 0-1024 characters. parse_mode (``str``, *optional*): By default, texts are parsed using both Markdown and HTML styles. You can combine both syntaxes together. Pass "markdown" to enable Markdown-style parsing only. Pass "html" to enable HTML-style parsing only. Pass None to completely disable style parsing. duration (``int``, *optional*): Duration of the audio in seconds. performer (``str``, *optional*): Performer. title (``str``, *optional*): Track name. thumb (``str``, *optional*): Thumbnail of the music file album cover. The thumbnail should be in JPEG format and less than 200 KB in size. A thumbnail's width and height should not exceed 320 pixels. Thumbnails can't be reused and can be only uploaded as a new file. disable_notification (``bool``, *optional*): Sends the message silently. Users will receive a notification with no sound. reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message. reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. progress (``callable``, *optional*): Pass a callback function to view the upload progress. The function must take *(client, current, total, \*args)* as positional arguments (look at the section below for a detailed description). progress_args (``tuple``, *optional*): Extra custom arguments for the progress callback function. Useful, for example, if you want to pass a chat_id and a message_id in order to edit a message with the updated progress. Other Parameters: client (:obj:`Client`): The Client itself, useful when you want to call other API methods inside the callback function. current (``int``): The amount of bytes uploaded so far. total (``int``): The size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. You can either keep *\*args* or add every single extra argument in your function signature. Returns: :obj:`Message` | ``None``: On success, the sent audio message is returned, otherwise, in case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. Raises: RPCError: In case of a Telegram RPC error. """ file = None try: if os.path.exists(audio): thumb = None if thumb is None else await self.save_file(thumb) file = await self.save_file(audio, progress=progress, progress_args=progress_args) media = types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(audio) or "audio/mpeg", file=file, thumb=thumb, attributes=[ types.DocumentAttributeAudio( duration=duration, performer=performer, title=title ), types.DocumentAttributeFilename(file_name=os.path.basename(audio)) ] ) elif audio.startswith("http"): media = types.InputMediaDocumentExternal( url=audio ) else: media = utils.get_input_media_from_file_id(audio, 9) while True: try: r = await self.send( functions.messages.SendMedia( peer=await self.resolve_peer(chat_id), media=media, silent=disable_notification or None, reply_to_msg_id=reply_to_message_id, random_id=self.rnd_id(), reply_markup=reply_markup.write() if reply_markup else None, **await self.parser.parse(caption, parse_mode) ) ) except FilePartMissing as e: await self.save_file(audio, file_id=file.id, file_part=e.x) else: for i in r.updates: if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)): return await pyrogram.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats} ) except BaseClient.StopTransmission: return None
def send_voice( self, chat_id: Union[int, str], voice: str, file_ref=None, caption: str = "", parse_mode: Union[str, None] = object, duration: int = 0, disable_notification: bool = None, reply_to_message_id: int = None, schedule_date: int = None, reply_markup: Union["pyrogram.InlineKeyboardMarkup", "pyrogram.ReplyKeyboardMarkup", "pyrogram.ReplyKeyboardRemove", "pyrogram.ForceReply"] = None, progress: callable = None, progress_args: tuple = () ) -> Union["pyrogram.Message", None]: """Send audio files. Parameters: chat_id (``int`` | ``str``): Unique identifier (int) or username (str) of the target chat. For your personal cloud (Saved Messages) you can simply use "me" or "self". For a contact that exists in your Telegram address book you can use his phone number (str). voice (``str``): Audio file to send. Pass a file_id as string to send an audio that exists on the Telegram servers, pass an HTTP URL as a string for Telegram to get an audio from the Internet, or pass a file path as string to upload a new audio that exists on your local machine. file_ref (``str``, *optional*): A valid file reference obtained by a recently fetched media message. To be used in combination with a file id in case a file reference is needed. caption (``str``, *optional*): Voice message caption, 0-1024 characters. parse_mode (``str``, *optional*): By default, texts are parsed using both Markdown and HTML styles. You can combine both syntaxes together. Pass "markdown" or "md" to enable Markdown-style parsing only. Pass "html" to enable HTML-style parsing only. Pass None to completely disable style parsing. duration (``int``, *optional*): Duration of the voice message in seconds. disable_notification (``bool``, *optional*): Sends the message silently. Users will receive a notification with no sound. reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message schedule_date (``int``, *optional*): Date when the message will be automatically sent. Unix time. reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. progress (``callable``, *optional*): Pass a callback function to view the file transmission progress. The function must take *(current, total)* as positional arguments (look at Other Parameters below for a detailed description) and will be called back each time a new file chunk has been successfully transmitted. progress_args (``tuple``, *optional*): Extra custom arguments for the progress callback function. You can pass anything you need to be available in the progress callback scope; for example, a Message object or a Client instance in order to edit the message with the updated progress status. Other Parameters: current (``int``): The amount of bytes transmitted so far. total (``int``): The total size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. You can either keep *\*args* or add every single extra argument in your function signature. Returns: :obj:`Message` | ``None``: On success, the sent voice message is returned, otherwise, in case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. Example: .. code-block:: python # Send voice note by uploading from local file app.send_voice("me", "voice.ogg") # Add caption to the voice note app.send_voice("me", "voice.ogg", caption="voice note") # Set voice note duration app.send_voice("me", "voice.ogg", duration=20) """ file = None try: if os.path.exists(voice): file = self.save_file(voice, progress=progress, progress_args=progress_args) media = types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(voice) or "audio/mpeg", file=file, attributes=[ types.DocumentAttributeAudio(voice=True, duration=duration) ]) elif voice.startswith("http"): media = types.InputMediaDocumentExternal(url=voice) else: media = utils.get_input_media_from_file_id(voice, file_ref, 3) while True: try: r = self.send( functions.messages.SendMedia( peer=self.resolve_peer(chat_id), media=media, silent=disable_notification or None, reply_to_msg_id=reply_to_message_id, random_id=self.rnd_id(), schedule_date=schedule_date, reply_markup=reply_markup.write() if reply_markup else None, **self.parser.parse(caption, parse_mode))) except FilePartMissing as e: self.save_file(voice, file_id=file.id, file_part=e.x) else: for i in r.updates: if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage, types.UpdateNewScheduledMessage)): return pyrogram.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, is_scheduled=isinstance( i, types.UpdateNewScheduledMessage)) except BaseClient.StopTransmission: return None
def send_voice( self, chat_id: Union[int, str], voice: str, caption: str = "", parse_mode: str = "", duration: int = 0, disable_notification: bool = None, reply_to_message_id: int = None, reply_markup: Union[ "pyrogram.InlineKeyboardMarkup", "pyrogram.ReplyKeyboardMarkup", "pyrogram.ReplyKeyboardRemove", "pyrogram.ForceReply" ] = None, progress: callable = None, progress_args: tuple = () ) -> Union["pyrogram.Message", None]: """Use this method to send audio files. Args: chat_id (``int`` | ``str``): Unique identifier (int) or username (str) of the target chat. For your personal cloud (Saved Messages) you can simply use "me" or "self". For a contact that exists in your Telegram address book you can use his phone number (str). voice (``str``): Audio file to send. Pass a file_id as string to send an audio that exists on the Telegram servers, pass an HTTP URL as a string for Telegram to get an audio from the Internet, or pass a file path as string to upload a new audio that exists on your local machine. caption (``str``, *optional*): Voice message caption, 0-1024 characters. parse_mode (``str``, *optional*): Use :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or :obj:`HTML <pyrogram.ParseMode.HTML>` if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your caption. Defaults to Markdown. duration (``int``, *optional*): Duration of the voice message in seconds. disable_notification (``bool``, *optional*): Sends the message silently. Users will receive a notification with no sound. reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. progress (``callable``, *optional*): Pass a callback function to view the upload progress. The function must take *(client, current, total, \*args)* as positional arguments (look at the section below for a detailed description). progress_args (``tuple``, *optional*): Extra custom arguments for the progress callback function. Useful, for example, if you want to pass a chat_id and a message_id in order to edit a message with the updated progress. Other Parameters: client (:obj:`Client <pyrogram.Client>`): The Client itself, useful when you want to call other API methods inside the callback function. current (``int``): The amount of bytes uploaded so far. total (``int``): The size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. You can either keep *\*args* or add every single extra argument in your function signature. Returns: On success, the sent :obj:`Message <pyrogram.Message>` is returned. In case the upload is deliberately stopped with :meth:`stop_transmission`, None is returned instead. Raises: :class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error. """ file = None style = self.html if parse_mode.lower() == "html" else self.markdown try: if os.path.exists(voice): file = self.save_file(voice, progress=progress, progress_args=progress_args) media = types.InputMediaUploadedDocument( mime_type="audio/mpeg", file=file, attributes=[ types.DocumentAttributeAudio( voice=True, duration=duration ) ] ) elif voice.startswith("http"): media = types.InputMediaDocumentExternal( url=voice ) else: try: decoded = utils.decode(voice) fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq" unpacked = struct.unpack(fmt, decoded) except (AssertionError, binascii.Error, struct.error): raise FileIdInvalid from None else: if unpacked[0] != 3: media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None) if media_type: raise FileIdInvalid("The file_id belongs to a {}".format(media_type)) else: raise FileIdInvalid("Unknown media type: {}".format(unpacked[0])) media = types.InputMediaDocument( id=types.InputDocument( id=unpacked[2], access_hash=unpacked[3], file_reference=b"" ) ) while True: try: r = self.send( functions.messages.SendMedia( peer=self.resolve_peer(chat_id), media=media, silent=disable_notification or None, reply_to_msg_id=reply_to_message_id, random_id=self.rnd_id(), reply_markup=reply_markup.write() if reply_markup else None, **style.parse(caption) ) ) except FilePartMissing as e: self.save_file(voice, file_id=file.id, file_part=e.x) else: for i in r.updates: if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)): return pyrogram.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats} ) except BaseClient.StopTransmission: return None
def send_video_note( self, chat_id: Union[int, str], video_note: str, file_ref: str = None, duration: int = 0, length: int = 1, thumb: str = None, disable_notification: bool = None, reply_to_message_id: int = None, schedule_date: int = None, reply_markup: Union[ "pyrogram.InlineKeyboardMarkup", "pyrogram.ReplyKeyboardMarkup", "pyrogram.ReplyKeyboardRemove", "pyrogram.ForceReply" ] = None, progress: callable = None, progress_args: tuple = () ) -> Union["pyrogram.Message", None]: """Send video messages. Parameters: chat_id (``int`` | ``str``): Unique identifier (int) or username (str) of the target chat. For your personal cloud (Saved Messages) you can simply use "me" or "self". For a contact that exists in your Telegram address book you can use his phone number (str). video_note (``str``): Video note to send. Pass a file_id as string to send a video note that exists on the Telegram servers, or pass a file path as string to upload a new video note that exists on your local machine. Sending video notes by a URL is currently unsupported. file_ref (``str``, *optional*): A valid file reference obtained by a recently fetched media message. To be used in combination with a file id in case a file reference is needed. duration (``int``, *optional*): Duration of sent video in seconds. length (``int``, *optional*): Video width and height. thumb (``str``, *optional*): Thumbnail of the video sent. The thumbnail should be in JPEG format and less than 200 KB in size. A thumbnail's width and height should not exceed 320 pixels. Thumbnails can't be reused and can be only uploaded as a new file. disable_notification (``bool``, *optional*): Sends the message silently. Users will receive a notification with no sound. reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message schedule_date (``int``, *optional*): Date when the message will be automatically sent. Unix time. reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. progress (``callable``, *optional*): Pass a callback function to view the file transmission progress. The function must take *(current, total)* as positional arguments (look at Other Parameters below for a detailed description) and will be called back each time a new file chunk has been successfully transmitted. progress_args (``tuple``, *optional*): Extra custom arguments for the progress callback function. You can pass anything you need to be available in the progress callback scope; for example, a Message object or a Client instance in order to edit the message with the updated progress status. Other Parameters: current (``int``): The amount of bytes transmitted so far. total (``int``): The total size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. You can either keep *\*args* or add every single extra argument in your function signature. Returns: :obj:`Message` | ``None``: On success, the sent video note message is returned, otherwise, in case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. Example: .. code-block:: python # Send video note by uploading from local file app.send_video_note("me", "video_note.mp4") # Set video note length app.send_video_note("me", "video_note.mp4", length=25) """ file = None try: if os.path.exists(video_note): thumb = None if thumb is None else self.save_file(thumb) file = self.save_file(video_note, progress=progress, progress_args=progress_args) media = types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(video_note) or "video/mp4", file=file, thumb=thumb, attributes=[ types.DocumentAttributeVideo( round_message=True, duration=duration, w=length, h=length ) ] ) else: media = utils.get_input_media_from_file_id(video_note, file_ref, 13) while True: try: r = self.send( functions.messages.SendMedia( peer=self.resolve_peer(chat_id), media=media, silent=disable_notification or None, reply_to_msg_id=reply_to_message_id, random_id=self.rnd_id(), schedule_date=schedule_date, reply_markup=reply_markup.write() if reply_markup else None, message="" ) ) except FilePartMissing as e: self.save_file(video_note, file_id=file.id, file_part=e.x) else: for i in r.updates: if isinstance( i, (types.UpdateNewMessage, types.UpdateNewChannelMessage, types.UpdateNewScheduledMessage) ): return pyrogram.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, is_scheduled=isinstance(i, types.UpdateNewScheduledMessage) ) except BaseClient.StopTransmission: return None
def send_animated_sticker( self, chat_id: Union[int, str], animated_sticker: str, disable_notification: bool = None, reply_to_message_id: int = None, reply_markup: Union[ "pyrogram.InlineKeyboardMarkup", "pyrogram.ReplyKeyboardMarkup", "pyrogram.ReplyKeyboardRemove", "pyrogram.ForceReply" ] = None, progress: callable = None, progress_args: tuple = () ) -> Union["pyrogram.Message", None]: """Send .tgs animated stickers. Parameters: chat_id (``int`` | ``str``): Unique identifier (int) or username (str) of the target chat. For your personal cloud (Saved Messages) you can simply use "me" or "self". For a contact that exists in your Telegram address book you can use his phone number (str). animated_sticker (``str``): Animated sticker to send. Pass a file_id as string to send a animated sticker that exists on the Telegram servers, pass an HTTP URL as a string for Telegram to get a .webp animated sticker file from the Internet, or pass a file path as string to upload a new animated sticker that exists on your local machine. disable_notification (``bool``, *optional*): Sends the message silently. Users will receive a notification with no sound. reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message. reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. progress (``callable``, *optional*): Pass a callback function to view the upload progress. The function must take *(client, current, total, \*args)* as positional arguments (look at the section below for a detailed description). progress_args (``tuple``, *optional*): Extra custom arguments for the progress callback function. Useful, for example, if you want to pass a chat_id and a message_id in order to edit a message with the updated progress. Other Parameters: client (:obj:`Client`): The Client itself, useful when you want to call other API methods inside the callback function. current (``int``): The amount of bytes uploaded so far. total (``int``): The size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. You can either keep *\*args* or add every single extra argument in your function signature. Returns: :obj:`Message` | ``None``: On success, the sent animated sticker message is returned, otherwise, in case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. Raises: RPCError: In case of a Telegram RPC error. """ file = None try: if os.path.exists(animated_sticker): file = self.save_file(animated_sticker, progress=progress, progress_args=progress_args) media = types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(animated_sticker) or "application/x-tgsticker", file=file, attributes=[ types.DocumentAttributeFilename(file_name=os.path.basename(animated_sticker)) ] ) elif animated_sticker.startswith("http"): media = types.InputMediaDocumentExternal( url=animated_sticker ) else: media = utils.get_input_media_from_file_id(animated_sticker, 5) while True: try: r = self.send( functions.messages.SendMedia( peer=self.resolve_peer(chat_id), media=media, silent=disable_notification or None, reply_to_msg_id=reply_to_message_id, random_id=self.rnd_id(), reply_markup=reply_markup.write() if reply_markup else None, message="" ) ) except FilePartMissing as e: self.save_file(animated_sticker, file_id=file.id, file_part=e.x) else: for i in r.updates: if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)): return pyrogram.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats} ) except BaseClient.StopTransmission: return None
def edit_message_media(self, chat_id: int or str, message_id: int, media, reply_markup=None): style = self.html if media.parse_mode.lower( ) == "html" else self.markdown caption = media.caption if isinstance(media, InputMediaPhoto): if os.path.exists(media.media): media = self.send( functions.messages.UploadMedia( peer=self.resolve_peer(chat_id), media=types.InputMediaUploadedPhoto( file=self.save_file(media.media)))) media = types.InputMediaPhoto(id=types.InputPhoto( id=media.photo.id, access_hash=media.photo.access_hash)) elif media.media.startswith("http"): media = types.InputMediaPhotoExternal(url=media.media) else: try: decoded = utils.decode(media.media) fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq" unpacked = struct.unpack(fmt, decoded) except (AssertionError, binascii.Error, struct.error): raise FileIdInvalid from None else: if unpacked[0] != 2: media_type = BaseClient.MEDIA_TYPE_ID.get( unpacked[0], None) if media_type: raise FileIdInvalid( "The file_id belongs to a {}".format( media_type)) else: raise FileIdInvalid( "Unknown media type: {}".format(unpacked[0])) media = types.InputMediaPhoto(id=types.InputPhoto( id=unpacked[2], access_hash=unpacked[3])) if isinstance(media, InputMediaVideo): if os.path.exists(media.media): media = self.send( functions.messages.UploadMedia( peer=self.resolve_peer(chat_id), media=types.InputMediaUploadedDocument( mime_type=mimetypes.types_map[".mp4"], file=self.save_file(media.media), attributes=[ types.DocumentAttributeVideo( supports_streaming=media.supports_streaming or None, duration=media.duration, w=media.width, h=media.height), types.DocumentAttributeFilename( os.path.basename(media.media)) ]))) media = types.InputMediaDocument(id=types.InputDocument( id=media.document.id, access_hash=media.document.access_hash)) elif media.media.startswith("http"): media = types.InputMediaDocumentExternal(url=media.media) else: try: decoded = utils.decode(media.media) fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq" unpacked = struct.unpack(fmt, decoded) except (AssertionError, binascii.Error, struct.error): raise FileIdInvalid from None else: if unpacked[0] != 4: media_type = BaseClient.MEDIA_TYPE_ID.get( unpacked[0], None) if media_type: raise FileIdInvalid( "The file_id belongs to a {}".format( media_type)) else: raise FileIdInvalid( "Unknown media type: {}".format(unpacked[0])) media = types.InputMediaDocument(id=types.InputDocument( id=unpacked[2], access_hash=unpacked[3])) if isinstance(media, InputMediaAudio): if os.path.exists(media.media): media = self.send( functions.messages.UploadMedia( peer=self.resolve_peer(chat_id), media=types.InputMediaUploadedDocument( mime_type=mimetypes.types_map.get( "." + media.media.split(".")[-1], "audio/mpeg"), file=self.save_file(media.media), attributes=[ types.DocumentAttributeAudio( duration=media.duration, performer=media.performer, title=media.title), types.DocumentAttributeFilename( os.path.basename(media.media)) ]))) media = types.InputMediaDocument(id=types.InputDocument( id=media.document.id, access_hash=media.document.access_hash)) elif media.media.startswith("http"): media = types.InputMediaDocumentExternal(url=media.media) else: try: decoded = utils.decode(media.media) fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq" unpacked = struct.unpack(fmt, decoded) except (AssertionError, binascii.Error, struct.error): raise FileIdInvalid from None else: if unpacked[0] != 9: media_type = BaseClient.MEDIA_TYPE_ID.get( unpacked[0], None) if media_type: raise FileIdInvalid( "The file_id belongs to a {}".format( media_type)) else: raise FileIdInvalid( "Unknown media type: {}".format(unpacked[0])) media = types.InputMediaDocument(id=types.InputDocument( id=unpacked[2], access_hash=unpacked[3])) if isinstance(media, InputMediaAnimation): if os.path.exists(media.media): media = self.send( functions.messages.UploadMedia( peer=self.resolve_peer(chat_id), media=types.InputMediaUploadedDocument( mime_type=mimetypes.types_map[".mp4"], file=self.save_file(media.media), attributes=[ types.DocumentAttributeVideo( supports_streaming=True, duration=media.duration, w=media.width, h=media.height), types.DocumentAttributeFilename( os.path.basename(media.media)), types.DocumentAttributeAnimated() ]))) media = types.InputMediaDocument(id=types.InputDocument( id=media.document.id, access_hash=media.document.access_hash)) elif media.media.startswith("http"): media = types.InputMediaDocumentExternal(url=media.media) else: try: decoded = utils.decode(media.media) fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq" unpacked = struct.unpack(fmt, decoded) except (AssertionError, binascii.Error, struct.error): raise FileIdInvalid from None else: if unpacked[0] != 10: media_type = BaseClient.MEDIA_TYPE_ID.get( unpacked[0], None) if media_type: raise FileIdInvalid( "The file_id belongs to a {}".format( media_type)) else: raise FileIdInvalid( "Unknown media type: {}".format(unpacked[0])) media = types.InputMediaDocument(id=types.InputDocument( id=unpacked[2], access_hash=unpacked[3])) if isinstance(media, InputMediaDocument): if os.path.exists(media.media): media = self.send( functions.messages.UploadMedia( peer=self.resolve_peer(chat_id), media=types.InputMediaUploadedDocument( mime_type=mimetypes.types_map.get( "." + media.media.split(".")[-1], "text/plain"), file=self.save_file(media.media), attributes=[ types.DocumentAttributeFilename( os.path.basename(media.media)) ]))) media = types.InputMediaDocument(id=types.InputDocument( id=media.document.id, access_hash=media.document.access_hash)) elif media.media.startswith("http"): media = types.InputMediaDocumentExternal(url=media.media) else: try: decoded = utils.decode(media.media) fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq" unpacked = struct.unpack(fmt, decoded) except (AssertionError, binascii.Error, struct.error): raise FileIdInvalid from None else: if unpacked[0] not in (5, 10): media_type = BaseClient.MEDIA_TYPE_ID.get( unpacked[0], None) if media_type: raise FileIdInvalid( "The file_id belongs to a {}".format( media_type)) else: raise FileIdInvalid( "Unknown media type: {}".format(unpacked[0])) media = types.InputMediaDocument(id=types.InputDocument( id=unpacked[2], access_hash=unpacked[3])) r = self.send( functions.messages.EditMessage( peer=self.resolve_peer(chat_id), id=message_id, reply_markup=reply_markup.write() if reply_markup else None, media=media, **style.parse(caption))) for i in r.updates: if isinstance( i, (types.UpdateEditMessage, types.UpdateEditChannelMessage)): return utils.parse_messages(self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats})
def send_sticker( self, chat_id: Union[int, str], sticker: Union[str, BinaryIO], file_ref: str = None, disable_notification: bool = None, reply_to_message_id: int = None, schedule_date: int = None, reply_markup: Union["pyrogram.InlineKeyboardMarkup", "pyrogram.ReplyKeyboardMarkup", "pyrogram.ReplyKeyboardRemove", "pyrogram.ForceReply"] = None, progress: callable = None, progress_args: tuple = () ) -> Union["pyrogram.Message", None]: """Send static .webp or animated .tgs stickers. Parameters: chat_id (``int`` | ``str``): Unique identifier (int) or username (str) of the target chat. For your personal cloud (Saved Messages) you can simply use "me" or "self". For a contact that exists in your Telegram address book you can use his phone number (str). sticker (``str`` | ``BinaryIO``): Sticker to send. Pass a file_id as string to send a sticker that exists on the Telegram servers, pass an HTTP URL as a string for Telegram to get a .webp sticker file from the Internet, pass a file path as string to upload a new sticker that exists on your local machine, or pass a binary file-like object with its attribute ".name" set for in-memory uploads. file_ref (``str``, *optional*): A valid file reference obtained by a recently fetched media message. To be used in combination with a file id in case a file reference is needed. disable_notification (``bool``, *optional*): Sends the message silently. Users will receive a notification with no sound. reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message. schedule_date (``int``, *optional*): Date when the message will be automatically sent. Unix time. reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. progress (``callable``, *optional*): Pass a callback function to view the file transmission progress. The function must take *(current, total)* as positional arguments (look at Other Parameters below for a detailed description) and will be called back each time a new file chunk has been successfully transmitted. progress_args (``tuple``, *optional*): Extra custom arguments for the progress callback function. You can pass anything you need to be available in the progress callback scope; for example, a Message object or a Client instance in order to edit the message with the updated progress status. Other Parameters: current (``int``): The amount of bytes transmitted so far. total (``int``): The total size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. You can either keep *\*args* or add every single extra argument in your function signature. Returns: :obj:`Message` | ``None``: On success, the sent sticker message is returned, otherwise, in case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. Example: .. code-block:: python # Send sticker by uploading from local file app.send_sticker("me", "sticker.webp") # Send sticker using file_id app.send_sticker("me", "CAADBAADzg4AAvLQYAEz_x2EOgdRwBYE") """ file = None try: if isinstance(sticker, str): if os.path.isfile(sticker): file = self.save_file(sticker, progress=progress, progress_args=progress_args) media = types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(sticker) or "image/webp", file=file, attributes=[ types.DocumentAttributeFilename( file_name=os.path.basename(sticker)) ]) elif re.match("^https?://", sticker): media = types.InputMediaDocumentExternal(url=sticker) else: media = utils.get_input_media_from_file_id( sticker, file_ref, 8) else: file = self.save_file(sticker, progress=progress, progress_args=progress_args) media = types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(sticker.name) or "image/webp", file=file, attributes=[ types.DocumentAttributeFilename(file_name=sticker.name) ]) while True: try: r = self.send( functions.messages.SendMedia( peer=self.resolve_peer(chat_id), media=media, silent=disable_notification or None, reply_to_msg_id=reply_to_message_id, random_id=self.rnd_id(), schedule_date=schedule_date, reply_markup=reply_markup.write() if reply_markup else None, message="")) except FilePartMissing as e: self.save_file(sticker, file_id=file.id, file_part=e.x) else: for i in r.updates: if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage, types.UpdateNewScheduledMessage)): return pyrogram.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, is_scheduled=isinstance( i, types.UpdateNewScheduledMessage)) except BaseClient.StopTransmission: return None
def send_document( self, chat_id: Union[int, str], document: Union[str, BinaryIO], file_ref: str = None, thumb: Union[str, BinaryIO] = None, caption: str = "", parse_mode: Union[str, None] = object, file_name: str = None, disable_notification: bool = None, reply_to_message_id: int = None, schedule_date: int = None, reply_markup: Union["pyrogram.InlineKeyboardMarkup", "pyrogram.ReplyKeyboardMarkup", "pyrogram.ReplyKeyboardRemove", "pyrogram.ForceReply"] = None, progress: callable = None, progress_args: tuple = () ) -> Union["pyrogram.Message", None]: """Send generic files. Parameters: chat_id (``int`` | ``str``): Unique identifier (int) or username (str) of the target chat. For your personal cloud (Saved Messages) you can simply use "me" or "self". For a contact that exists in your Telegram address book you can use his phone number (str). document (``str`` | ``BinaryIO``): File to send. Pass a file_id as string to send a file that exists on the Telegram servers, pass an HTTP URL as a string for Telegram to get a file from the Internet, pass a file path as string to upload a new file that exists on your local machine, or pass a binary file-like object with its attribute ".name" set for in-memory uploads. file_ref (``str``, *optional*): A valid file reference obtained by a recently fetched media message. To be used in combination with a file id in case a file reference is needed. thumb (``str`` | ``BinaryIO``, *optional*): Thumbnail of the file sent. The thumbnail should be in JPEG format and less than 200 KB in size. A thumbnail's width and height should not exceed 320 pixels. Thumbnails can't be reused and can be only uploaded as a new file. caption (``str``, *optional*): Document caption, 0-1024 characters. parse_mode (``str``, *optional*): By default, texts are parsed using both Markdown and HTML styles. You can combine both syntaxes together. Pass "markdown" or "md" to enable Markdown-style parsing only. Pass "html" to enable HTML-style parsing only. Pass None to completely disable style parsing. file_name (``str``, *optional*): File name of the document sent. Defaults to file's path basename. disable_notification (``bool``, *optional*): Sends the message silently. Users will receive a notification with no sound. reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message. schedule_date (``int``, *optional*): Date when the message will be automatically sent. Unix time. reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. progress (``callable``, *optional*): Pass a callback function to view the file transmission progress. The function must take *(current, total)* as positional arguments (look at Other Parameters below for a detailed description) and will be called back each time a new file chunk has been successfully transmitted. progress_args (``tuple``, *optional*): Extra custom arguments for the progress callback function. You can pass anything you need to be available in the progress callback scope; for example, a Message object or a Client instance in order to edit the message with the updated progress status. Other Parameters: current (``int``): The amount of bytes transmitted so far. total (``int``): The total size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. You can either keep *\*args* or add every single extra argument in your function signature. Returns: :obj:`Message` | ``None``: On success, the sent document message is returned, otherwise, in case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. Example: .. code-block:: python # Send document by uploading from local file app.send_document("me", "document.zip") # Add caption to the document file app.send_document("me", "document.zip", caption="archive") # Keep track of the progress while uploading def progress(current, total): print("{:.1f}%".format(current * 100 / total)) app.send_document("me", "document.zip", progress=progress) """ file = None try: if isinstance(document, str): if os.path.isfile(document): thumb = self.save_file(thumb) file = self.save_file(document, progress=progress, progress_args=progress_args) media = types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(document) or "application/zip", file=file, force_file=True, thumb=thumb, attributes=[ types.DocumentAttributeFilename( file_name=file_name or os.path.basename(document)) ]) elif re.match("^https?://", document): media = types.InputMediaDocumentExternal(url=document) else: media = utils.get_input_media_from_file_id( document, file_ref, 5) else: thumb = self.save_file(thumb) file = self.save_file(document, progress=progress, progress_args=progress_args) media = types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(document.name) or "application/zip", file=file, thumb=thumb, attributes=[ types.DocumentAttributeFilename( file_name=document.name) ]) while True: try: r = self.send( functions.messages.SendMedia( peer=self.resolve_peer(chat_id), media=media, silent=disable_notification or None, reply_to_msg_id=reply_to_message_id, random_id=self.rnd_id(), schedule_date=schedule_date, reply_markup=reply_markup.write() if reply_markup else None, **self.parser.parse(caption, parse_mode))) except FilePartMissing as e: self.save_file(document, file_id=file.id, file_part=e.x) else: for i in r.updates: if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage, types.UpdateNewScheduledMessage)): return pyrogram.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, is_scheduled=isinstance( i, types.UpdateNewScheduledMessage)) except BaseClient.StopTransmission: return None
def edit_message_media( self, chat_id: Union[int, str], message_id: int, media: InputMedia, reply_markup: "pyrogram.InlineKeyboardMarkup" = None ) -> "pyrogram.Message": """Edit animation, audio, document, photo or video messages. If a message is a part of a message album, then it can be edited only to a photo or a video. Otherwise, the message type can be changed arbitrarily. Parameters: chat_id (``int`` | ``str``): Unique identifier (int) or username (str) of the target chat. For your personal cloud (Saved Messages) you can simply use "me" or "self". For a contact that exists in your Telegram address book you can use his phone number (str). message_id (``int``): Message identifier in the chat specified in chat_id. media (:obj:`InputMedia`): One of the InputMedia objects describing an animation, audio, document, photo or video. reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): An InlineKeyboardMarkup object. Returns: :obj:`Message`: On success, the edited message is returned. Example: .. code-block:: python from pyrogram import InputMediaPhoto, InputMediaVideo, InputMediaAudio # Replace the current media with a local photo app.edit_message_media(chat_id, message_id, InputMediaPhoto("new_photo.jpg")) # Replace the current media with a local video app.edit_message_media(chat_id, message_id, InputMediaVideo("new_video.mp4")) # Replace the current media with a local audio app.edit_message_media(chat_id, message_id, InputMediaAudio("new_audio.mp3")) """ caption = media.caption parse_mode = media.parse_mode if isinstance(media, InputMediaPhoto): if os.path.exists(media.media): media = self.send( functions.messages.UploadMedia( peer=self.resolve_peer(chat_id), media=types.InputMediaUploadedPhoto( file=self.save_file(media.media)))) media = types.InputMediaPhoto( id=types.InputPhoto(id=media.photo.id, access_hash=media.photo.access_hash, file_reference=b"")) elif media.media.startswith("http"): media = types.InputMediaPhotoExternal(url=media.media) else: media = utils.get_input_media_from_file_id( media.media, media.file_ref, 2) elif isinstance(media, InputMediaVideo): if os.path.exists(media.media): media = self.send( functions.messages.UploadMedia( peer=self.resolve_peer(chat_id), media=types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(media.media) or "video/mp4", thumb=None if media.thumb is None else self.save_file(media.thumb), file=self.save_file(media.media), attributes=[ types.DocumentAttributeVideo( supports_streaming=media.supports_streaming or None, duration=media.duration, w=media.width, h=media.height), types.DocumentAttributeFilename( file_name=os.path.basename(media.media)) ]))) media = types.InputMediaDocument(id=types.InputDocument( id=media.document.id, access_hash=media.document.access_hash, file_reference=b"")) elif media.media.startswith("http"): media = types.InputMediaDocumentExternal(url=media.media) else: media = utils.get_input_media_from_file_id( media.media, media.file_ref, 4) elif isinstance(media, InputMediaAudio): if os.path.exists(media.media): media = self.send( functions.messages.UploadMedia( peer=self.resolve_peer(chat_id), media=types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(media.media) or "audio/mpeg", thumb=None if media.thumb is None else self.save_file(media.thumb), file=self.save_file(media.media), attributes=[ types.DocumentAttributeAudio( duration=media.duration, performer=media.performer, title=media.title), types.DocumentAttributeFilename( file_name=os.path.basename(media.media)) ]))) media = types.InputMediaDocument(id=types.InputDocument( id=media.document.id, access_hash=media.document.access_hash, file_reference=b"")) elif media.media.startswith("http"): media = types.InputMediaDocumentExternal(url=media.media) else: media = utils.get_input_media_from_file_id( media.media, media.file_ref, 9) elif isinstance(media, InputMediaAnimation): if os.path.exists(media.media): media = self.send( functions.messages.UploadMedia( peer=self.resolve_peer(chat_id), media=types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(media.media) or "video/mp4", thumb=None if media.thumb is None else self.save_file(media.thumb), file=self.save_file(media.media), attributes=[ types.DocumentAttributeVideo( supports_streaming=True, duration=media.duration, w=media.width, h=media.height), types.DocumentAttributeFilename( file_name=os.path.basename(media.media)), types.DocumentAttributeAnimated() ]))) media = types.InputMediaDocument(id=types.InputDocument( id=media.document.id, access_hash=media.document.access_hash, file_reference=b"")) elif media.media.startswith("http"): media = types.InputMediaDocumentExternal(url=media.media) else: media = utils.get_input_media_from_file_id( media.media, media.file_ref, 10) elif isinstance(media, InputMediaDocument): if os.path.exists(media.media): media = self.send( functions.messages.UploadMedia( peer=self.resolve_peer(chat_id), media=types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(media.media) or "application/zip", thumb=None if media.thumb is None else self.save_file(media.thumb), file=self.save_file(media.media), attributes=[ types.DocumentAttributeFilename( file_name=os.path.basename(media.media)) ]))) media = types.InputMediaDocument(id=types.InputDocument( id=media.document.id, access_hash=media.document.access_hash, file_reference=b"")) elif media.media.startswith("http"): media = types.InputMediaDocumentExternal(url=media.media) else: media = utils.get_input_media_from_file_id( media.media, media.file_ref, 5) r = self.send( functions.messages.EditMessage( peer=self.resolve_peer(chat_id), id=message_id, media=media, reply_markup=reply_markup.write() if reply_markup else None, **self.parser.parse(caption, parse_mode))) for i in r.updates: if isinstance( i, (types.UpdateEditMessage, types.UpdateEditChannelMessage)): return pyrogram.Message._parse(self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats})
def send_audio(self, chat_id: int or str, audio: str, caption: str = "", parse_mode: str = "", duration: int = 0, performer: str = None, title: str = None, thumb: str = None, disable_notification: bool = None, reply_to_message_id: int = None, reply_markup=None, progress: callable = None, progress_args: tuple = ()): """Use this method to send audio files. For sending voice messages, use the :obj:`send_voice()` method instead. Args: chat_id (``int`` | ``str``): Unique identifier (int) or username (str) of the target chat. For your personal cloud (Saved Messages) you can simply use "me" or "self". For a contact that exists in your Telegram address book you can use his phone number (str). audio (``str``): Audio file to send. Pass a file_id as string to send an audio file that exists on the Telegram servers, pass an HTTP URL as a string for Telegram to get an audio file from the Internet, or pass a file path as string to upload a new audio file that exists on your local machine. caption (``str``, *optional*): Audio caption, 0-200 characters. parse_mode (``str``, *optional*): Use :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or :obj:`HTML <pyrogram.ParseMode.HTML>` if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your caption. Defaults to Markdown. duration (``int``, *optional*): Duration of the audio in seconds. performer (``str``, *optional*): Performer. title (``str``, *optional*): Track name. thumb (``str``, *optional*): Thumbnail of the music file album cover. The thumbnail should be in JPEG format and less than 200 KB in size. A thumbnail's width and height should not exceed 90 pixels. Thumbnails can't be reused and can be only uploaded as a new file. disable_notification (``bool``, *optional*): Sends the message silently. Users will receive a notification with no sound. reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message. reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. progress (``callable``, *optional*): Pass a callback function to view the upload progress. The function must take *(client, current, total, \*args)* as positional arguments (look at the section below for a detailed description). progress_args (``tuple``, *optional*): Extra custom arguments for the progress callback function. Useful, for example, if you want to pass a chat_id and a message_id in order to edit a message with the updated progress. Other Parameters: client (:obj:`Client <pyrogram.Client>`): The Client itself, useful when you want to call other API methods inside the callback function. current (``int``): The amount of bytes uploaded so far. total (``int``): The size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the *progress_args* parameter. You can either keep *\*args* or add every single extra argument in your function signature. Returns: On success, the sent :obj:`Message <pyrogram.Message>` is returned. Raises: :class:`Error <pyrogram.Error>` """ file = None style = self.html if parse_mode.lower() == "html" else self.markdown if os.path.exists(audio): thumb = None if thumb is None else self.save_file(thumb) file = self.save_file(audio, progress=progress, progress_args=progress_args) media = types.InputMediaUploadedDocument( mime_type=mimetypes.types_map.get("." + audio.split(".")[-1], "audio/mpeg"), file=file, thumb=thumb, attributes=[ types.DocumentAttributeAudio(duration=duration, performer=performer, title=title), types.DocumentAttributeFilename(os.path.basename(audio)) ]) elif audio.startswith("http"): media = types.InputMediaDocumentExternal(url=audio) else: try: decoded = utils.decode(audio) fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq" unpacked = struct.unpack(fmt, decoded) except (AssertionError, binascii.Error, struct.error): raise FileIdInvalid from None else: if unpacked[0] != 9: media_type = BaseClient.MEDIA_TYPE_ID.get( unpacked[0], None) if media_type: raise FileIdInvalid( "The file_id belongs to a {}".format(media_type)) else: raise FileIdInvalid("Unknown media type: {}".format( unpacked[0])) media = types.InputMediaDocument(id=types.InputDocument( id=unpacked[2], access_hash=unpacked[3])) while True: try: r = self.send( functions.messages.SendMedia( peer=self.resolve_peer(chat_id), media=media, silent=disable_notification or None, reply_to_msg_id=reply_to_message_id, random_id=self.rnd_id(), reply_markup=reply_markup.write() if reply_markup else None, **style.parse(caption))) except FilePartMissing as e: self.save_file(audio, file_id=file.id, file_part=e.x) else: for i in r.updates: if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)): return utils.parse_messages(self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats})
def send_media_group(self, chat_id: Union[int, str], media: List[Union["pyrogram.InputMediaPhoto", "pyrogram.InputMediaVideo"]], disable_notification: bool = None, reply_to_message_id: int = None): """Use this method to send a group of photos or videos as an album. On success, an Update containing the sent Messages is returned. Args: chat_id (``int`` | ``str``): Unique identifier (int) or username (str) of the target chat. For your personal cloud (Saved Messages) you can simply use "me" or "self". For a contact that exists in your Telegram address book you can use his phone number (str). media (``list``): A list containing either :obj:`InputMediaPhoto <pyrogram.InputMediaPhoto>` or :obj:`InputMediaVideo <pyrogram.InputMediaVideo>` objects describing photos and videos to be sent, must include 2–10 items. disable_notification (``bool``, *optional*): Sends the message silently. Users will receive a notification with no sound. reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message. """ multi_media = [] for i in media: style = self.html if i.parse_mode.lower( ) == "html" else self.markdown if isinstance(i, pyrogram.InputMediaPhoto): if os.path.exists(i.media): media = self.send( functions.messages.UploadMedia( peer=self.resolve_peer(chat_id), media=types.InputMediaUploadedPhoto( file=self.save_file(i.media)))) media = types.InputMediaPhoto(id=types.InputPhoto( id=media.photo.id, access_hash=media.photo.access_hash, file_reference=b"")) else: try: decoded = utils.decode(i.media) fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq" unpacked = struct.unpack(fmt, decoded) except (AssertionError, binascii.Error, struct.error): raise FileIdInvalid from None else: if unpacked[0] != 2: media_type = BaseClient.MEDIA_TYPE_ID.get( unpacked[0], None) if media_type: raise FileIdInvalid( "The file_id belongs to a {}".format( media_type)) else: raise FileIdInvalid( "Unknown media type: {}".format( unpacked[0])) media = types.InputMediaPhoto( id=types.InputPhoto(id=unpacked[2], access_hash=unpacked[3], file_reference=b"")) elif isinstance(i, pyrogram.InputMediaVideo): if os.path.exists(i.media): media = self.send( functions.messages.UploadMedia( peer=self.resolve_peer(chat_id), media=types.InputMediaUploadedDocument( file=self.save_file(i.media), thumb=None if i.thumb is None else self.save_file(i.thumb), mime_type=mimetypes.types_map[".mp4"], attributes=[ types.DocumentAttributeVideo( supports_streaming=i.supports_streaming or None, duration=i.duration, w=i.width, h=i.height), types.DocumentAttributeFilename( os.path.basename(i.media)) ]))) media = types.InputMediaDocument(id=types.InputDocument( id=media.document.id, access_hash=media.document.access_hash, file_reference=b"")) else: try: decoded = utils.decode(i.media) fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq" unpacked = struct.unpack(fmt, decoded) except (AssertionError, binascii.Error, struct.error): raise FileIdInvalid from None else: if unpacked[0] != 4: media_type = BaseClient.MEDIA_TYPE_ID.get( unpacked[0], None) if media_type: raise FileIdInvalid( "The file_id belongs to a {}".format( media_type)) else: raise FileIdInvalid( "Unknown media type: {}".format( unpacked[0])) media = types.InputMediaDocument( id=types.InputDocument(id=unpacked[2], access_hash=unpacked[3], file_reference=b"")) multi_media.append( types.InputSingleMedia(media=media, random_id=self.rnd_id(), **style.parse(i.caption))) return self.send( functions.messages.SendMultiMedia( peer=self.resolve_peer(chat_id), multi_media=multi_media, silent=disable_notification or None, reply_to_msg_id=reply_to_message_id))