diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py index b68bd891..1efb6f06 100644 --- a/pyrogram/client/client.py +++ b/pyrogram/client/client.py @@ -1715,7 +1715,7 @@ class Client(Methods, BaseClient): def save_file( self, - path: str, + path: Union[str, io.IOBase], file_id: int = None, file_part: int = 0, progress: callable = None, @@ -1767,9 +1767,20 @@ class Client(Methods, BaseClient): Raises: RPCError: In case of a Telegram RPC error. + ValueError: if path is not str or file-like readable object """ part_size = 512 * 1024 - file_size = os.path.getsize(path) + if isinstance(path, str): + fp = open(path, 'rb') + filename = os.path.basename(path) + elif hasattr(path, 'write'): + fp = path + filename = fp.name + else: + raise ValueError("Invalid path passed! Pass file pointer or path to file") + fp.seek(0, os.SEEK_END) + file_size = fp.tell() + fp.seek(0) if file_size == 0: raise ValueError("File size equals to 0 B") @@ -1787,67 +1798,74 @@ class Client(Methods, BaseClient): session.start() try: - with open(path, "rb") as f: - f.seek(part_size * file_part) + fp.seek(part_size * file_part) - while True: - chunk = f.read(part_size) - - if not chunk: - if not is_big: - md5_sum = "".join([hex(i)[2:].zfill(2) for i in md5_sum.digest()]) - break - - for _ in range(3): - if is_big: - rpc = functions.upload.SaveBigFilePart( - file_id=file_id, - file_part=file_part, - file_total_parts=file_total_parts, - bytes=chunk - ) - else: - rpc = functions.upload.SaveFilePart( - file_id=file_id, - file_part=file_part, - bytes=chunk - ) - - if session.send(rpc): - break - else: - raise AssertionError("Telegram didn't accept chunk #{} of {}".format(file_part, path)) - - if is_missing_part: - return + while True: + chunk = fp.read(part_size) + if not chunk: if not is_big: - md5_sum.update(chunk) + md5_sum = "".join([hex(i)[2:].zfill(2) for i in md5_sum.digest()]) + break - file_part += 1 + for _ in range(3): + if is_big: + rpc = functions.upload.SaveBigFilePart( + file_id=file_id, + file_part=file_part, + file_total_parts=file_total_parts, + bytes=chunk + ) + else: + rpc = functions.upload.SaveFilePart( + file_id=file_id, + file_part=file_part, + bytes=chunk + ) - if progress: - progress(min(file_part * part_size, file_size), file_size, *progress_args) + if session.send(rpc): + break + else: + raise AssertionError("Telegram didn't accept chunk #{} of {}".format(file_part, path)) + + if is_missing_part: + return + + if not is_big: + md5_sum.update(chunk) + + file_part += 1 + + if progress: + progress(min(file_part * part_size, file_size), file_size, *progress_args) except Client.StopTransmission: + if isinstance(path, str): + fp.close() raise except Exception as e: + if isinstance(path, str): + fp.close() log.error(e, exc_info=True) else: + if isinstance(path, str): + fp.close() if is_big: return types.InputFileBig( id=file_id, parts=file_total_parts, - name=os.path.basename(path), + name=filename, ) else: return types.InputFile( id=file_id, parts=file_total_parts, - name=os.path.basename(path), + name=filename, md5_checksum=md5_sum ) finally: + if isinstance(path, str): + fp.close() session.stop() def get_file( diff --git a/pyrogram/client/methods/messages/send_animated_sticker.py b/pyrogram/client/methods/messages/send_animated_sticker.py new file mode 100644 index 00000000..b2959394 --- /dev/null +++ b/pyrogram/client/methods/messages/send_animated_sticker.py @@ -0,0 +1,153 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2019 Dan Tès +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . +import io +import os +from typing import Union + +import pyrogram +from pyrogram.api import functions, types +from pyrogram.client.ext import BaseClient, utils +from pyrogram.errors import FilePartMissing + + +class SendAnimatedSticker(BaseClient): + def send_animated_sticker( + self, + chat_id: Union[int, str], + animated_sticker: Union[str, io.IOBase], + 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`` | file-like object): + 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. + pass a readable file-like object with .name + + 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 isinstance(animated_sticker, str): + 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) + elif hasattr(animated_sticker, "read"): + file = self.save_file(animated_sticker, progress=progress, progress_args=progress_args) + media = types.InputMediaUploadedDocument( + mime_type=self.guess_mime_type(animated_sticker.name) or "application/x-tgsticker", + file=file, + attributes=[ + types.DocumentAttributeFilename(file_name=animated_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(), + 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 diff --git a/pyrogram/client/methods/messages/send_animation.py b/pyrogram/client/methods/messages/send_animation.py index 288ed04e..f8078a7c 100644 --- a/pyrogram/client/methods/messages/send_animation.py +++ b/pyrogram/client/methods/messages/send_animation.py @@ -15,7 +15,7 @@ # # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . - +import io import os from typing import Union @@ -29,6 +29,7 @@ class SendAnimation(BaseClient): def send_animation( self, chat_id: Union[int, str], + animation: Union[str, io.IOBase], animation: str, file_ref: str = None, caption: str = "", @@ -59,11 +60,13 @@ class SendAnimation(BaseClient): 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 (``str``| file-like object): 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. + pass a readable file-like object with .name + file_ref (``str``, *optional*): A valid file reference obtained by a recently fetched media message. @@ -163,11 +166,36 @@ class SendAnimation(BaseClient): file = None try: - if os.path.exists(animation): + if isinstance(animation, str): + 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=file_name or 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, file_ref, 10) + elif hasattr(animation, "read"): 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", + mime_type=self.guess_mime_type(animation.name) or "video/mp4", file=file, thumb=thumb, attributes=[ @@ -177,17 +205,10 @@ class SendAnimation(BaseClient): w=width, h=height ), - types.DocumentAttributeFilename(file_name=file_name or os.path.basename(animation)), + types.DocumentAttributeFilename(file_name=animation.name), types.DocumentAttributeAnimated() ] ) - elif animation.startswith("http"): - media = types.InputMediaDocumentExternal( - url=animation - ) - else: - media = utils.get_input_media_from_file_id(animation, file_ref, 10) - while True: try: r = self.send( diff --git a/pyrogram/client/methods/messages/send_audio.py b/pyrogram/client/methods/messages/send_audio.py index e271d96c..0ff588d8 100644 --- a/pyrogram/client/methods/messages/send_audio.py +++ b/pyrogram/client/methods/messages/send_audio.py @@ -15,7 +15,7 @@ # # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . - +import io import os from typing import Union @@ -29,6 +29,7 @@ class SendAudio(BaseClient): def send_audio( self, chat_id: Union[int, str], + audio: Union[str, io.IOBase], audio: str, file_ref: str = None, caption: str = "", @@ -60,11 +61,12 @@ class SendAudio(BaseClient): 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 (``str``, file-like object): 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. + pass a readable file-like object with .name file_ref (``str``, *optional*): A valid file reference obtained by a recently fetched media message. @@ -163,11 +165,34 @@ class SendAudio(BaseClient): file = None try: - if os.path.exists(audio): + if isinstance(audio, str): + 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=file_name or 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) + elif hasattr(audio, "read"): 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", + mime_type=self.guess_mime_type(audio.name) or "audio/mpeg", file=file, thumb=thumb, attributes=[ @@ -176,15 +201,9 @@ class SendAudio(BaseClient): performer=performer, title=title ), - types.DocumentAttributeFilename(file_name=file_name or os.path.basename(audio)) + types.DocumentAttributeFilename(file_name=os.path.basename(audio.name)) ] ) - 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: diff --git a/pyrogram/client/methods/messages/send_document.py b/pyrogram/client/methods/messages/send_document.py index 24a754f0..c4a7252b 100644 --- a/pyrogram/client/methods/messages/send_document.py +++ b/pyrogram/client/methods/messages/send_document.py @@ -15,7 +15,7 @@ # # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . - +import io import os from typing import Union @@ -29,6 +29,7 @@ class SendDocument(BaseClient): def send_document( self, chat_id: Union[int, str], + document: Union[str, io.IOBase], document: str, file_ref: str = None, thumb: str = None, @@ -60,6 +61,8 @@ class SendDocument(BaseClient): 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. + pass a readable file-like object with .name + file_ref (``str``, *optional*): A valid file reference obtained by a recently fetched media message. @@ -143,23 +146,35 @@ class SendDocument(BaseClient): file = None try: - if os.path.exists(document): + if isinstance(document, str): + if os.path.exists(document): + thumb = None if thumb is None else 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, + thumb=thumb, + attributes=[ + types.DocumentAttributeFilename(file_name=file_name or os.path.basename(document)) + ] + ) + elif document.startswith("http"): + media = types.InputMediaDocumentExternal( + url=document + ) + else: + media = utils.get_input_media_from_file_id(document, file_ref, 5) + else: thumb = None if thumb is None else 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", + mime_type=self.guess_mime_type(document.name) or "application/zip", file=file, thumb=thumb, attributes=[ - types.DocumentAttributeFilename(file_name=file_name or os.path.basename(document)) + types.DocumentAttributeFilename(file_name=document.name) ] ) - elif document.startswith("http"): - media = types.InputMediaDocumentExternal( - url=document - ) - else: - media = utils.get_input_media_from_file_id(document, file_ref, 5) while True: try: diff --git a/pyrogram/client/methods/messages/send_photo.py b/pyrogram/client/methods/messages/send_photo.py index 4d6a18a3..7877c986 100644 --- a/pyrogram/client/methods/messages/send_photo.py +++ b/pyrogram/client/methods/messages/send_photo.py @@ -15,7 +15,7 @@ # # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . - +import io import os from typing import Union @@ -29,6 +29,7 @@ class SendPhoto(BaseClient): def send_photo( self, chat_id: Union[int, str], + photo: Union[str, io.IOBase], photo: str, file_ref: str = None, caption: str = "", @@ -54,11 +55,12 @@ class SendPhoto(BaseClient): 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). - photo (``str``): + photo (``str`` | file-like object): Photo to send. Pass a file_id as string to send a photo that exists on the Telegram servers, pass an HTTP URL as a string for Telegram to get a photo from the Internet, or pass a file path as string to upload a new photo that exists on your local machine. + pass a readable file-like object with .name file_ref (``str``, *optional*): A valid file reference obtained by a recently fetched media message. @@ -137,19 +139,26 @@ class SendPhoto(BaseClient): file = None try: - if os.path.exists(photo): + if isinstance(photo, str): + if os.path.exists(photo): + file = self.save_file(photo, progress=progress, progress_args=progress_args) + media = types.InputMediaUploadedPhoto( + file=file, + ttl_seconds=ttl_seconds + ) + elif photo.startswith("http"): + media = types.InputMediaPhotoExternal( + url=photo, + ttl_seconds=ttl_seconds + ) + else: + media = utils.get_input_media_from_file_id(photo, file_ref, 2) + elif hasattr(photo, "read"): file = self.save_file(photo, progress=progress, progress_args=progress_args) media = types.InputMediaUploadedPhoto( file=file, ttl_seconds=ttl_seconds ) - elif photo.startswith("http"): - media = types.InputMediaPhotoExternal( - url=photo, - ttl_seconds=ttl_seconds - ) - else: - media = utils.get_input_media_from_file_id(photo, file_ref, 2) while True: try: diff --git a/pyrogram/client/methods/messages/send_sticker.py b/pyrogram/client/methods/messages/send_sticker.py index 76a42d3d..98cc4425 100644 --- a/pyrogram/client/methods/messages/send_sticker.py +++ b/pyrogram/client/methods/messages/send_sticker.py @@ -15,7 +15,7 @@ # # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . - +import io import os from typing import Union @@ -29,6 +29,7 @@ class SendSticker(BaseClient): def send_sticker( self, chat_id: Union[int, str], + sticker: Union[str, io.IOBase], sticker: str, file_ref: str = None, disable_notification: bool = None, @@ -56,6 +57,7 @@ class SendSticker(BaseClient): 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. + pass a readable file-like object with .name file_ref (``str``, *optional*): A valid file reference obtained by a recently fetched media message. @@ -113,21 +115,31 @@ class SendSticker(BaseClient): file = None try: - if os.path.exists(sticker): + if isinstance(sticker, str): + if os.path.exists(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 sticker.startswith("http"): + media = types.InputMediaDocumentExternal( + url=sticker + ) + else: + media = utils.get_input_media_from_file_id(sticker, file_ref, 8) + elif hasattr(sticker, "read"): 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)) + types.DocumentAttributeFilename(file_name=sticker.name) ] ) - 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: diff --git a/pyrogram/client/methods/messages/send_video.py b/pyrogram/client/methods/messages/send_video.py index fc58aa98..6c1c2efe 100644 --- a/pyrogram/client/methods/messages/send_video.py +++ b/pyrogram/client/methods/messages/send_video.py @@ -15,7 +15,7 @@ # # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . - +import io import os from typing import Union @@ -29,6 +29,7 @@ class SendVideo(BaseClient): def send_video( self, chat_id: Union[int, str], + video: Union[str, io.IOBase], video: str, file_ref: str = None, caption: str = "", @@ -64,6 +65,7 @@ class SendVideo(BaseClient): Pass a file_id as string to send a video that exists on the Telegram servers, pass an HTTP URL as a string for Telegram to get a video from the Internet, or pass a file path as string to upload a new video that exists on your local machine. + pass a readable file-like object with .name file_ref (``str``, *optional*): A valid file reference obtained by a recently fetched media message. @@ -160,11 +162,35 @@ class SendVideo(BaseClient): file = None try: - if os.path.exists(video): + if isinstance(video, str): + if os.path.exists(video): + thumb = None if thumb is None else self.save_file(thumb) + file = self.save_file(video, progress=progress, progress_args=progress_args) + media = types.InputMediaUploadedDocument( + mime_type=self.guess_mime_type(video) or "video/mp4", + file=file, + thumb=thumb, + attributes=[ + types.DocumentAttributeVideo( + supports_streaming=supports_streaming or None, + duration=duration, + w=width, + h=height + ), + types.DocumentAttributeFilename(file_name=file_name or os.path.basename(video)) + ] + ) + elif video.startswith("http"): + media = types.InputMediaDocumentExternal( + url=video + ) + else: + media = utils.get_input_media_from_file_id(video, file_ref, 4) + elif hasattr(video, "read"): thumb = None if thumb is None else self.save_file(thumb) file = self.save_file(video, progress=progress, progress_args=progress_args) media = types.InputMediaUploadedDocument( - mime_type=self.guess_mime_type(video) or "video/mp4", + mime_type=self.guess_mime_type(video.name) or "video/mp4", file=file, thumb=thumb, attributes=[ @@ -174,15 +200,9 @@ class SendVideo(BaseClient): w=width, h=height ), - types.DocumentAttributeFilename(file_name=file_name or os.path.basename(video)) + types.DocumentAttributeFilename(file_name=video.name) ] ) - elif video.startswith("http"): - media = types.InputMediaDocumentExternal( - url=video - ) - else: - media = utils.get_input_media_from_file_id(video, file_ref, 4) while True: try: diff --git a/pyrogram/client/methods/messages/send_video_note.py b/pyrogram/client/methods/messages/send_video_note.py index 64bde11b..a160567d 100644 --- a/pyrogram/client/methods/messages/send_video_note.py +++ b/pyrogram/client/methods/messages/send_video_note.py @@ -15,7 +15,7 @@ # # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . - +import io import os from typing import Union @@ -29,6 +29,7 @@ class SendVideoNote(BaseClient): def send_video_note( self, chat_id: Union[int, str], + video_note: Union[str, io.IOBase], video_note: str, file_ref: str = None, duration: int = 0, @@ -54,11 +55,12 @@ class SendVideoNote(BaseClient): 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 (``str``, file-like object): 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. + pass a readable file-like object with .name file_ref (``str``, *optional*): A valid file reference obtained by a recently fetched media message. @@ -128,11 +130,30 @@ class SendVideoNote(BaseClient): file = None try: - if os.path.exists(video_note): + if isinstance(video_note, str): + 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) + elif hasattr(video_note, "read"): 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", + mime_type=self.guess_mime_type(video_note.name) or "video/mp4", file=file, thumb=thumb, attributes=[ @@ -144,8 +165,6 @@ class SendVideoNote(BaseClient): ) ] ) - else: - media = utils.get_input_media_from_file_id(video_note, file_ref, 13) while True: try: diff --git a/pyrogram/client/methods/messages/send_voice.py b/pyrogram/client/methods/messages/send_voice.py index 753e3806..e57a652e 100644 --- a/pyrogram/client/methods/messages/send_voice.py +++ b/pyrogram/client/methods/messages/send_voice.py @@ -15,7 +15,7 @@ # # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . - +import io import os from typing import Union @@ -29,6 +29,7 @@ class SendVoice(BaseClient): def send_voice( self, chat_id: Union[int, str], + voice: Union[str, io.IOBase], voice: str, file_ref=None, caption: str = "", @@ -54,11 +55,12 @@ class SendVoice(BaseClient): 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``): + voice (``str``, file-like object): 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. + pass a readable file-like object with .name file_ref (``str``, *optional*): A valid file reference obtained by a recently fetched media message. @@ -132,11 +134,30 @@ class SendVoice(BaseClient): file = None try: - if os.path.exists(voice): + if isinstance(voice, str): + 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) + elif hasattr(voice, "read"): 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, + mime_type=self.guess_mime_type(voice.name) or "audio/mpeg", + file=file.name, attributes=[ types.DocumentAttributeAudio( voice=True, @@ -144,12 +165,6 @@ class SendVoice(BaseClient): ) ] ) - 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: