From b3faf21c95533232a71bbb7049d316ab18725c28 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Thu, 9 Jul 2020 02:56:09 +0200 Subject: [PATCH] Rework in-memory uploads --- pyrogram/client/client.py | 35 +++++++++---- .../client/methods/messages/send_animation.py | 52 +++++++++++++------ .../client/methods/messages/send_audio.py | 50 ++++++++++++------ .../client/methods/messages/send_document.py | 45 ++++++++++------ .../client/methods/messages/send_photo.py | 34 +++++++----- .../client/methods/messages/send_sticker.py | 39 +++++++++----- .../client/methods/messages/send_video.py | 51 ++++++++++++------ .../methods/messages/send_video_note.py | 40 ++++++++++---- .../client/methods/messages/send_voice.py | 40 +++++++++----- 9 files changed, 260 insertions(+), 126 deletions(-) diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py index 0e186d85..c46f119a 100644 --- a/pyrogram/client/client.py +++ b/pyrogram/client/client.py @@ -16,6 +16,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . +import io import logging import math import os @@ -30,7 +31,7 @@ from importlib import import_module, reload from pathlib import Path from signal import signal, SIGINT, SIGTERM, SIGABRT from threading import Thread -from typing import Union, List +from typing import Union, List, BinaryIO from pyrogram.api import functions, types from pyrogram.api.core import TLObject @@ -39,9 +40,9 @@ from pyrogram.client.handlers.handler import Handler from pyrogram.client.methods.password.utils import compute_check from pyrogram.crypto import AES from pyrogram.errors import ( - PhoneMigrate, NetworkMigrate, SessionPasswordNeeded, - FloodWait, PeerIdInvalid, VolumeLocNotFound, UserMigrate, ChannelPrivate, AuthBytesInvalid, - BadRequest) + PhoneMigrate, NetworkMigrate, SessionPasswordNeeded, PeerIdInvalid, VolumeLocNotFound, UserMigrate, ChannelPrivate, + AuthBytesInvalid, BadRequest +) from pyrogram.session import Auth, Session from .ext import utils, Syncer, BaseClient, Dispatcher from .methods import Methods @@ -1713,7 +1714,7 @@ class Client(Methods, BaseClient): def save_file( self, - path: str, + path: Union[str, BinaryIO], file_id: int = None, file_part: int = 0, progress: callable = None, @@ -1767,7 +1768,19 @@ class Client(Methods, BaseClient): RPCError: In case of a Telegram RPC error. """ part_size = 512 * 1024 - file_size = os.path.getsize(path) + + if isinstance(path, str): + fp = open(path, "rb") + elif isinstance(path, io.IOBase): + fp = path + else: + raise ValueError("Invalid file. Expected a file path as string or a binary (not text) file pointer") + + file_name = fp.name + + 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") @@ -1785,11 +1798,11 @@ class Client(Methods, BaseClient): session.start() try: - with open(path, "rb") as f: - f.seek(part_size * file_part) + with fp: + fp.seek(part_size * file_part) while True: - chunk = f.read(part_size) + chunk = fp.read(part_size) if not chunk: if not is_big: @@ -1835,14 +1848,14 @@ class Client(Methods, BaseClient): return types.InputFileBig( id=file_id, parts=file_total_parts, - name=os.path.basename(path), + name=file_name, ) else: return types.InputFile( id=file_id, parts=file_total_parts, - name=os.path.basename(path), + name=file_name, md5_checksum=md5_sum ) finally: diff --git a/pyrogram/client/methods/messages/send_animation.py b/pyrogram/client/methods/messages/send_animation.py index c84e0503..a38856a0 100644 --- a/pyrogram/client/methods/messages/send_animation.py +++ b/pyrogram/client/methods/messages/send_animation.py @@ -18,7 +18,7 @@ import os import re -from typing import Union +from typing import Union, BinaryIO import pyrogram from pyrogram.api import functions, types @@ -30,7 +30,7 @@ class SendAnimation(BaseClient): def send_animation( self, chat_id: Union[int, str], - animation: str, + animation: Union[str, BinaryIO], file_ref: str = None, caption: str = "", unsave: bool = False, @@ -38,7 +38,7 @@ class SendAnimation(BaseClient): duration: int = 0, width: int = 0, height: int = 0, - thumb: str = None, + thumb: Union[str, BinaryIO] = None, file_name: str = None, disable_notification: bool = None, reply_to_message_id: int = None, @@ -60,11 +60,12 @@ 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`` | ``BinaryIO``): 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 an HTTP URL as a string for Telegram to get an animation from the Internet, + pass a file path as string to upload a new animation 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. @@ -93,7 +94,7 @@ class SendAnimation(BaseClient): height (``int``, *optional*): Animation height. - thumb (``str``, *optional*): + thumb (``str`` | ``BinaryIO``, *optional*): Thumbnail of the animation file sent. The thumbnail should be in JPEG format and less than 200 KB in size. A thumbnail's width and height should not exceed 320 pixels. @@ -164,11 +165,36 @@ class SendAnimation(BaseClient): file = None try: - if os.path.isfile(animation): + if isinstance(animation, str): + if os.path.isfile(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 re.match("^https?://", animation): + media = types.InputMediaDocumentExternal( + url=animation + ) + else: + media = utils.get_input_media_from_file_id(animation, file_ref, 10) + else: 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=[ @@ -178,16 +204,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 re.match("^https?://", animation): - media = types.InputMediaDocumentExternal( - url=animation - ) - else: - media = utils.get_input_media_from_file_id(animation, file_ref, 10) while True: try: diff --git a/pyrogram/client/methods/messages/send_audio.py b/pyrogram/client/methods/messages/send_audio.py index 49fd0e09..08c03d07 100644 --- a/pyrogram/client/methods/messages/send_audio.py +++ b/pyrogram/client/methods/messages/send_audio.py @@ -18,7 +18,7 @@ import os import re -from typing import Union +from typing import Union, BinaryIO import pyrogram from pyrogram.api import functions, types @@ -30,14 +30,14 @@ class SendAudio(BaseClient): def send_audio( self, chat_id: Union[int, str], - audio: str, + audio: Union[str, BinaryIO], file_ref: str = None, caption: str = "", parse_mode: Union[str, None] = object, duration: int = 0, performer: str = None, title: str = None, - thumb: str = None, + thumb: Union[str, BinaryIO] = None, file_name: str = None, disable_notification: bool = None, reply_to_message_id: int = None, @@ -61,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`` | ``BinaryIO``): 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 an HTTP URL as a string for Telegram to get an audio file from the Internet, + pass a file path as string to upload a new audio file that exists on your local machine, or + pass a binary file-like object with its attribute ".name" set for in-memory uploads. file_ref (``str``, *optional*): A valid file reference obtained by a recently fetched media message. @@ -90,7 +91,7 @@ class SendAudio(BaseClient): title (``str``, *optional*): Track name. - thumb (``str``, *optional*): + thumb (``str`` | ``BinaryIO``, *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. @@ -164,11 +165,34 @@ class SendAudio(BaseClient): file = None try: - if os.path.isfile(audio): + if isinstance(audio, str): + if os.path.isfile(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 re.match("^https?://", audio): + media = types.InputMediaDocumentExternal( + url=audio + ) + else: + media = utils.get_input_media_from_file_id(audio, file_ref, 9) + else: 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=[ @@ -177,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=audio.name) ] ) - elif re.match("^https?://", audio): - 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 8f15c5ee..2241754b 100644 --- a/pyrogram/client/methods/messages/send_document.py +++ b/pyrogram/client/methods/messages/send_document.py @@ -18,7 +18,7 @@ import os import re -from typing import Union +from typing import Union, BinaryIO import pyrogram from pyrogram.api import functions, types @@ -30,9 +30,9 @@ class SendDocument(BaseClient): def send_document( self, chat_id: Union[int, str], - document: str, + document: Union[str, BinaryIO], file_ref: str = None, - thumb: str = None, + thumb: Union[str, BinaryIO] = None, caption: str = "", parse_mode: Union[str, None] = object, file_name: str = None, @@ -56,17 +56,18 @@ class SendDocument(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). - document (``str``): + document (``str`` | ``BinaryIO``): File to send. Pass a file_id as string to send a file that exists on the Telegram servers, - pass an HTTP URL as a string for Telegram to get a file from the Internet, or - pass a file path as string to upload a new file that exists on your local machine. + pass an HTTP URL as a string for Telegram to get a file from the Internet, + pass a file path as string to upload a new file that exists on your local machine, or + pass a binary file-like object with its attribute ".name" set for in-memory uploads. file_ref (``str``, *optional*): A valid file reference obtained by a recently fetched media message. To be used in combination with a file id in case a file reference is needed. - thumb (``str``, *optional*): + thumb (``str`` | ``BinaryIO``, *optional*): Thumbnail of the file sent. The thumbnail should be in JPEG format and less than 200 KB in size. A thumbnail's width and height should not exceed 320 pixels. @@ -144,23 +145,35 @@ class SendDocument(BaseClient): file = None try: - if os.path.isfile(document): + if isinstance(document, str): + if os.path.isfile(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 re.match("^https?://", document): + 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 re.match("^https?://", document): - 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 c21bb487..63101685 100644 --- a/pyrogram/client/methods/messages/send_photo.py +++ b/pyrogram/client/methods/messages/send_photo.py @@ -18,7 +18,7 @@ import os import re -from typing import Union +from typing import Union, BinaryIO import pyrogram from pyrogram.api import functions, types @@ -30,7 +30,7 @@ class SendPhoto(BaseClient): def send_photo( self, chat_id: Union[int, str], - photo: str, + photo: Union[str, BinaryIO], file_ref: str = None, caption: str = "", parse_mode: Union[str, None] = object, @@ -55,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`` | ``BinaryIO``): 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 an HTTP URL as a string for Telegram to get a photo from the Internet, + pass a file path as string to upload a new photo 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. @@ -138,19 +139,26 @@ class SendPhoto(BaseClient): file = None try: - if os.path.isfile(photo): + if isinstance(photo, str): + if os.path.isfile(photo): + file = self.save_file(photo, progress=progress, progress_args=progress_args) + media = types.InputMediaUploadedPhoto( + file=file, + ttl_seconds=ttl_seconds + ) + elif re.match("^https?://", photo): + media = types.InputMediaPhotoExternal( + url=photo, + ttl_seconds=ttl_seconds + ) + else: + media = utils.get_input_media_from_file_id(photo, file_ref, 2) + else: file = self.save_file(photo, progress=progress, progress_args=progress_args) media = types.InputMediaUploadedPhoto( file=file, ttl_seconds=ttl_seconds ) - elif re.match("^https?://", photo): - 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 d9575885..0de47d64 100644 --- a/pyrogram/client/methods/messages/send_sticker.py +++ b/pyrogram/client/methods/messages/send_sticker.py @@ -18,7 +18,7 @@ import os import re -from typing import Union +from typing import Union, BinaryIO import pyrogram from pyrogram.api import functions, types @@ -30,7 +30,7 @@ class SendSticker(BaseClient): def send_sticker( self, chat_id: Union[int, str], - sticker: str, + sticker: Union[str, BinaryIO], file_ref: str = None, disable_notification: bool = None, reply_to_message_id: int = None, @@ -52,11 +52,12 @@ class SendSticker(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). - sticker (``str``): + sticker (``str`` | ``BinaryIO``): Sticker to send. Pass a file_id as string to send a sticker that exists on the Telegram servers, - pass an HTTP URL as a string for Telegram to get a .webp sticker file from the Internet, or - pass a file path as string to upload a new sticker that exists on your local machine. + pass an HTTP URL as a string for Telegram to get a .webp sticker file from the Internet, + pass a file path as string to upload a new sticker that exists on your local machine, or + pass a binary file-like object with its attribute ".name" set for in-memory uploads. file_ref (``str``, *optional*): A valid file reference obtained by a recently fetched media message. @@ -114,21 +115,31 @@ class SendSticker(BaseClient): file = None try: - if os.path.isfile(sticker): + if isinstance(sticker, str): + if os.path.isfile(sticker): + file = self.save_file(sticker, progress=progress, progress_args=progress_args) + media = types.InputMediaUploadedDocument( + mime_type=self.guess_mime_type(sticker) or "image/webp", + file=file, + attributes=[ + types.DocumentAttributeFilename(file_name=os.path.basename(sticker)) + ] + ) + elif re.match("^https?://", sticker): + media = types.InputMediaDocumentExternal( + url=sticker + ) + else: + media = utils.get_input_media_from_file_id(sticker, file_ref, 8) + else: file = self.save_file(sticker, progress=progress, progress_args=progress_args) media = types.InputMediaUploadedDocument( - mime_type=self.guess_mime_type(sticker) or "image/webp", + mime_type=self.guess_mime_type(sticker.name) or "image/webp", file=file, attributes=[ - types.DocumentAttributeFilename(file_name=os.path.basename(sticker)) + types.DocumentAttributeFilename(file_name=sticker.name) ] ) - elif re.match("^https?://", sticker): - 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 9a67bbbb..1f46252f 100644 --- a/pyrogram/client/methods/messages/send_video.py +++ b/pyrogram/client/methods/messages/send_video.py @@ -18,7 +18,7 @@ import os import re -from typing import Union +from typing import Union, BinaryIO import pyrogram from pyrogram.api import functions, types @@ -30,14 +30,14 @@ class SendVideo(BaseClient): def send_video( self, chat_id: Union[int, str], - video: str, + video: Union[str, BinaryIO], file_ref: str = None, caption: str = "", parse_mode: Union[str, None] = object, duration: int = 0, width: int = 0, height: int = 0, - thumb: str = None, + thumb: Union[str, BinaryIO] = None, file_name: str = None, supports_streaming: bool = True, disable_notification: bool = None, @@ -60,11 +60,12 @@ class SendVideo(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 (``str``): + video (``str`` | ``BinaryIO``): Video to send. 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 an HTTP URL as a string for Telegram to get a video from the Internet, + pass a file path as string to upload a new video 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. @@ -89,7 +90,7 @@ class SendVideo(BaseClient): height (``int``, *optional*): Video height. - thumb (``str``, *optional*): + thumb (``str`` | ``BinaryIO``, *optional*): Thumbnail of the video sent. The thumbnail should be in JPEG format and less than 200 KB in size. A thumbnail's width and height should not exceed 320 pixels. @@ -161,11 +162,35 @@ class SendVideo(BaseClient): file = None try: - if os.path.isfile(video): + if isinstance(video, str): + if os.path.isfile(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 re.match("^https?://", video): + media = types.InputMediaDocumentExternal( + url=video + ) + else: + media = utils.get_input_media_from_file_id(video, file_ref, 4) + else: 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=[ @@ -175,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 re.match("^https?://", video): - 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 b7acdc01..829f1459 100644 --- a/pyrogram/client/methods/messages/send_video_note.py +++ b/pyrogram/client/methods/messages/send_video_note.py @@ -17,7 +17,7 @@ # along with Pyrogram. If not, see . import os -from typing import Union +from typing import Union, BinaryIO import pyrogram from pyrogram.api import functions, types @@ -29,11 +29,11 @@ class SendVideoNote(BaseClient): def send_video_note( self, chat_id: Union[int, str], - video_note: str, + video_note: Union[str, BinaryIO], file_ref: str = None, duration: int = 0, length: int = 1, - thumb: str = None, + thumb: Union[str, BinaryIO] = None, disable_notification: bool = None, reply_to_message_id: int = None, schedule_date: int = None, @@ -54,10 +54,11 @@ 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`` | ``BinaryIO``): 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. + Pass a file_id as string to send a video note that exists on the Telegram servers, + pass a file path as string to upload a new video note that exists on your local machine, or + pass a binary file-like object with its attribute ".name" set for in-memory uploads. Sending video notes by a URL is currently unsupported. file_ref (``str``, *optional*): @@ -70,7 +71,7 @@ class SendVideoNote(BaseClient): length (``int``, *optional*): Video width and height. - thumb (``str``, *optional*): + thumb (``str`` | ``BinaryIO``, *optional*): Thumbnail of the video sent. The thumbnail should be in JPEG format and less than 200 KB in size. A thumbnail's width and height should not exceed 320 pixels. @@ -128,11 +129,30 @@ class SendVideoNote(BaseClient): file = None try: - if os.path.isfile(video_note): + if isinstance(video_note, str): + if os.path.isfile(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) + else: 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 +164,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 23492f53..f99b4236 100644 --- a/pyrogram/client/methods/messages/send_voice.py +++ b/pyrogram/client/methods/messages/send_voice.py @@ -18,7 +18,7 @@ import os import re -from typing import Union +from typing import Union, BinaryIO import pyrogram from pyrogram.api import functions, types @@ -30,7 +30,7 @@ class SendVoice(BaseClient): def send_voice( self, chat_id: Union[int, str], - voice: str, + voice: Union[str, BinaryIO], file_ref=None, caption: str = "", parse_mode: Union[str, None] = object, @@ -55,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`` | ``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, or - pass a file path as string to upload a new audio that exists on your local machine. + 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. @@ -133,10 +134,29 @@ class SendVoice(BaseClient): file = None try: - if os.path.isfile(voice): + 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) or "audio/mpeg", + mime_type=self.guess_mime_type(voice.name) or "audio/mpeg", file=file, attributes=[ types.DocumentAttributeAudio( @@ -145,12 +165,6 @@ class SendVoice(BaseClient): ) ] ) - elif re.match("^https?://", voice): - media = types.InputMediaDocumentExternal( - url=voice - ) - else: - media = utils.get_input_media_from_file_id(voice, file_ref, 3) while True: try: