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:`Error <pyrogram.Error>` 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=mimetypes.types_map.get( "." + voice.split(".")[-1], "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_audio( self, chat_id: Union[int, str], audio: str, file_ref: str = None, caption: str = "", parse_mode: Union[str, None] = object, duration: int = 0, performer: str = None, title: str = None, 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 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. 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*): 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" 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 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. 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 audio message is returned, otherwise, in case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. Example: .. code-block:: python :emphasize-lines: 2,5,8-10,13-16 # Send audio file by uploading from file app.send_audio("me", "audio.mp3") # Add caption to the audio app.send_audio("me", "audio.mp3", caption="shoegaze") # Set audio metadata app.send_audio( "me", "audio.mp3", title="Printemps émeraude", performer="Alcest", duration=440) # Keep track of the progress while uploading def progress(current, total): print("{:.1f}%".format(current * 100 / total)) app.send_audio("me", "audio.mp3", progress=progress) """ file = None try: 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=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, file_ref, 9) 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(audio, 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_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 self.save_file(thumb) file = 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 = 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, **self.parser.parse(caption, parse_mode) ) ) 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 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: Union[int, str], message_id: int, media: InputMedia, reply_markup: "pyrogram.InlineKeyboardMarkup" = None ) -> "pyrogram.Message": """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. 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. Raises: 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 = 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, 2) 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=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, 4) 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=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, 9) 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=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, 10) 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=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, 5) 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 pyrogram.Message._parse(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": """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 = 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=media.photo.file_reference ) ) 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 = await self.send( functions.messages.UploadMedia( peer=await 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 await 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=media.document.file_reference ) ) 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 = await self.send( functions.messages.UploadMedia( peer=await 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 await 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=media.document.file_reference ) ) 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 = await self.send( functions.messages.UploadMedia( peer=await 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=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=media.document.file_reference ) ) 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 = await self.send( functions.messages.UploadMedia( peer=await 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 await 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=media.document.file_reference ) ) 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 = await self.send( functions.messages.EditMessage( peer=await self.resolve_peer(chat_id), id=message_id, media=media, reply_markup=reply_markup.write() if reply_markup else None, **await self.parser.parse(caption, parse_mode) ) ) 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} )
def send_voice( self, chat_id: Union[int, str], voice: Union[str, BinaryIO], 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`` | ``BinaryIO``): 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, pass a file path as string to upload a new audio 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. 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 isinstance(voice, str): if os.path.isfile(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 re.match("^https?://", voice): media = types.InputMediaDocumentExternal(url=voice) else: media = utils.get_input_media_from_file_id( voice, file_ref, 3) else: file = self.save_file(voice, progress=progress, progress_args=progress_args) media = types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(voice.name) or "audio/mpeg", file=file, attributes=[ types.DocumentAttributeAudio(voice=True, duration=duration) ]) 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
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})
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})