def write(self): try: decoded = utils.decode(self.audio_file_id) 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])) audio = types.InputDocument(id=unpacked[2], access_hash=unpacked[3]) return types.InputBotInlineResultDocument( id=self.id, type="audio", document=audio, send_message=types.InputBotInlineMessageMediaAuto( reply_markup=self.reply_markup.write() if self.reply_markup else None, **self.style.parse(self.caption)))
async def send_document( self, chat_id: Union[int, str], document: str, thumb: str = None, caption: str = "", parse_mode: 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]: """Use this method to send general 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). document (``str``): 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, or pass a file path as string to upload a new file that exists on your local machine. thumb (``str``, *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 90 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*): 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. 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(document): thumb = None if thumb is None else await self.save_file(thumb) file = await self.save_file(document, progress=progress, progress_args=progress_args) media = types.InputMediaUploadedDocument( mime_type="application/zip", file=file, thumb=thumb, attributes=[ types.DocumentAttributeFilename( file_name=os.path.basename(document)) ]) elif document.startswith("http"): media = types.InputMediaDocumentExternal(url=document) else: try: decoded = utils.decode(document) 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"")) 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 style.parse(caption))) except FilePartMissing as e: await 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)): 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
async def send_cached_media( self, chat_id: Union[int, str], file_id: str, caption: str = "", parse_mode: str = "", disable_notification: bool = None, reply_to_message_id: int = None, reply_markup: Union["pyrogram.InlineKeyboardMarkup", "pyrogram.ReplyKeyboardMarkup", "pyrogram.ReplyKeyboardRemove", "pyrogram.ForceReply"] = None ) -> Union["pyrogram.Message", None]: """Use this method to send any media stored on the Telegram servers using a file_id. This convenience method works with any valid file_id only. It does the same as calling the relevant method for sending media using a file_id, thus saving you from the hassle of using the correct method for the media the file_id is pointing to. 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). file_id (``str``): Media to send. Pass a file_id as string to send a media that exists on the Telegram servers. caption (``bool``, *optional*): Media 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. 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. Returns: On success, the sent :obj:`Message <pyrogram.Message>` is returned. Raises: :class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error. """ style = self.html if parse_mode.lower() == "html" else self.markdown try: decoded = utils.decode(file_id) fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq" unpacked = struct.unpack(fmt, decoded) except (AssertionError, binascii.Error, struct.error): raise FileIdInvalid from None else: media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None) if not media_type: raise FileIdInvalid("Unknown media type: {}".format( unpacked[0])) if media_type == "photo": media = types.InputMediaPhoto( id=types.InputPhoto(id=unpacked[2], access_hash=unpacked[3], file_reference=b"")) else: media = types.InputMediaDocument( id=types.InputDocument(id=unpacked[2], access_hash=unpacked[3], file_reference=b"")) 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 style.parse(caption))) 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})
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))
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})