diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py index 7cbaace0..6c787baa 100644 --- a/pyrogram/client/client.py +++ b/pyrogram/client/client.py @@ -17,6 +17,7 @@ # along with Pyrogram. If not, see . import asyncio +import io import logging import math import os @@ -28,7 +29,7 @@ from hashlib import sha256, md5 from importlib import import_module, reload from pathlib import Path from signal import signal, SIGINT, SIGTERM, SIGABRT -from typing import Union, List +from typing import Union, List, BinaryIO from pyrogram.api import functions, types from pyrogram.api.core import TLObject @@ -38,8 +39,9 @@ from pyrogram.client.methods.password.utils import compute_check from pyrogram.crypto import AES from pyrogram.errors import ( PhoneMigrate, NetworkMigrate, SessionPasswordNeeded, - PeerIdInvalid, VolumeLocNotFound, UserMigrate, ChannelPrivate, AuthBytesInvalid, - BadRequest) + PeerIdInvalid, VolumeLocNotFound, UserMigrate, ChannelPrivate, + AuthBytesInvalid, BadRequest +) from pyrogram.session import Auth, Session from .ext import utils, Syncer, BaseClient, Dispatcher from .ext.utils import ainput @@ -1714,13 +1716,14 @@ class Client(Methods, BaseClient): except KeyError: raise PeerIdInvalid - async def save_file(self, - path: str, - file_id: int = None, - file_part: int = 0, - progress: callable = None, - progress_args: tuple = () - ): + async def save_file( + self, + path: Union[str, BinaryIO], + file_id: int = None, + file_part: int = 0, + progress: callable = None, + progress_args: tuple = () + ): """Upload a file onto Telegram servers, without actually sending the message to anyone. Useful whenever an InputFile type is required. @@ -1782,7 +1785,19 @@ class Client(Methods, BaseClient): logging.error(e) 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") @@ -1805,11 +1820,11 @@ class Client(Methods, BaseClient): for session in pool: await session.start() - 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: @@ -1851,14 +1866,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/chats/set_chat_photo.py b/pyrogram/client/methods/chats/set_chat_photo.py index 16f9750e..5a7d37ae 100644 --- a/pyrogram/client/methods/chats/set_chat_photo.py +++ b/pyrogram/client/methods/chats/set_chat_photo.py @@ -63,7 +63,7 @@ class SetChatPhoto(BaseClient): """ peer = await self.resolve_peer(chat_id) - if os.path.exists(photo): + if os.path.isfile(photo): photo = types.InputChatUploadedPhoto(file=await self.save_file(photo)) else: photo = utils.get_input_media_from_file_id(photo, file_ref, 2) diff --git a/pyrogram/client/methods/chats/set_slow_mode.py b/pyrogram/client/methods/chats/set_slow_mode.py index 445abd4b..185a3824 100644 --- a/pyrogram/client/methods/chats/set_slow_mode.py +++ b/pyrogram/client/methods/chats/set_slow_mode.py @@ -26,7 +26,7 @@ class SetSlowMode(BaseClient): async def set_slow_mode( self, chat_id: Union[int, str], - seconds: int, + seconds: Union[int, None] ) -> bool: """Set the slow mode interval for a chat. @@ -34,9 +34,9 @@ class SetSlowMode(BaseClient): chat_id (``int`` | ``str``): Unique identifier (int) or username (str) of the target chat. - seconds (``int`` | ``str``): + seconds (``int`` | ``None``): Seconds in which members will be able to send only one message per this interval. - Valid values are: 0 (off), 10, 30, 60 (1m), 300 (5m), 900 (15m) or 3600 (1h). + Valid values are: 0 or None (off), 10, 30, 60 (1m), 300 (5m), 900 (15m) or 3600 (1h). Returns: ``bool``: True on success. @@ -44,13 +44,17 @@ class SetSlowMode(BaseClient): Example: .. code-block:: python + # Set slow mode to 60 seconds app.set_slow_mode("pyrogramchat", 60) + + # Disable slow mode + app.set_slow_mode("pyrogramchat", None) """ await self.send( functions.channels.ToggleSlowMode( channel=await self.resolve_peer(chat_id), - seconds=seconds + seconds=0 if seconds is None else seconds ) ) diff --git a/pyrogram/client/methods/messages/edit_inline_media.py b/pyrogram/client/methods/messages/edit_inline_media.py index 86ed21c4..74cb2910 100644 --- a/pyrogram/client/methods/messages/edit_inline_media.py +++ b/pyrogram/client/methods/messages/edit_inline_media.py @@ -16,6 +16,8 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . +import re + import pyrogram from pyrogram.api import functions, types from pyrogram.client.ext import BaseClient, utils @@ -72,35 +74,35 @@ class EditInlineMedia(BaseClient): parse_mode = media.parse_mode if isinstance(media, InputMediaPhoto): - if media.media.startswith("http"): + if re.match("^https?://", media.media): 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 media.media.startswith("http"): + if re.match("^https?://", media.media): 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 media.media.startswith("http"): + if re.match("^https?://", media.media): 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 media.media.startswith("http"): + if re.match("^https?://", media.media): 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 media.media.startswith("http"): + if re.match("^https?://", media.media): media = types.InputMediaDocumentExternal( url=media.media ) diff --git a/pyrogram/client/methods/messages/edit_message_media.py b/pyrogram/client/methods/messages/edit_message_media.py index b5b73ae6..d9ab74db 100644 --- a/pyrogram/client/methods/messages/edit_message_media.py +++ b/pyrogram/client/methods/messages/edit_message_media.py @@ -17,6 +17,7 @@ # along with Pyrogram. If not, see . import os +import re from typing import Union import pyrogram @@ -78,7 +79,7 @@ class EditMessageMedia(BaseClient): parse_mode = media.parse_mode if isinstance(media, InputMediaPhoto): - if os.path.exists(media.media): + if os.path.isfile(media.media): media = await self.send( functions.messages.UploadMedia( peer=await self.resolve_peer(chat_id), @@ -95,14 +96,14 @@ class EditMessageMedia(BaseClient): file_reference=media.photo.file_reference ) ) - elif media.media.startswith("http"): + elif re.match("^https?://", media.media): 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): + if os.path.isfile(media.media): media = await self.send( functions.messages.UploadMedia( peer=await self.resolve_peer(chat_id), @@ -132,14 +133,14 @@ class EditMessageMedia(BaseClient): file_reference=media.document.file_reference ) ) - elif media.media.startswith("http"): + elif re.match("^https?://", media.media): 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): + if os.path.isfile(media.media): media = await self.send( functions.messages.UploadMedia( peer=await self.resolve_peer(chat_id), @@ -168,14 +169,14 @@ class EditMessageMedia(BaseClient): file_reference=media.document.file_reference ) ) - elif media.media.startswith("http"): + elif re.match("^https?://", media.media): 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): + if os.path.isfile(media.media): media = await self.send( functions.messages.UploadMedia( peer=await self.resolve_peer(chat_id), @@ -206,14 +207,14 @@ class EditMessageMedia(BaseClient): file_reference=media.document.file_reference ) ) - elif media.media.startswith("http"): + elif re.match("^https?://", media.media): 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): + if os.path.isfile(media.media): media = await self.send( functions.messages.UploadMedia( peer=await self.resolve_peer(chat_id), @@ -237,7 +238,7 @@ class EditMessageMedia(BaseClient): file_reference=media.document.file_reference ) ) - elif media.media.startswith("http"): + elif re.match("^https?://", media.media): media = types.InputMediaDocumentExternal( url=media.media ) diff --git a/pyrogram/client/methods/messages/send_animation.py b/pyrogram/client/methods/messages/send_animation.py index 14b46b97..8f5b9ea0 100644 --- a/pyrogram/client/methods/messages/send_animation.py +++ b/pyrogram/client/methods/messages/send_animation.py @@ -17,7 +17,8 @@ # along with Pyrogram. If not, see . import os -from typing import Union +import re +from typing import Union, BinaryIO import pyrogram from pyrogram.api import functions, types @@ -29,7 +30,7 @@ class SendAnimation(BaseClient): async def send_animation( self, chat_id: Union[int, str], - animation: str, + animation: Union[str, BinaryIO], file_ref: str = None, caption: str = "", unsave: bool = False, @@ -37,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, @@ -59,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. @@ -92,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. @@ -163,11 +165,36 @@ class SendAnimation(BaseClient): file = None try: - if os.path.exists(animation): + if isinstance(animation, str): + if os.path.isfile(animation): + thumb = None if thumb is None else await self.save_file(thumb) + file = await 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 await self.save_file(thumb) file = await 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,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 animation.startswith("http"): - 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 1aba6045..f5b4a385 100644 --- a/pyrogram/client/methods/messages/send_audio.py +++ b/pyrogram/client/methods/messages/send_audio.py @@ -17,7 +17,8 @@ # along with Pyrogram. If not, see . import os -from typing import Union +import re +from typing import Union, BinaryIO import pyrogram from pyrogram.api import functions, types @@ -29,14 +30,14 @@ class SendAudio(BaseClient): async 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,file_name: str = None, + thumb: Union[str, BinaryIO] = None,file_name: str = None, disable_notification: bool = None, reply_to_message_id: int = None, schedule_date: int = None, @@ -59,11 +60,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. @@ -88,7 +90,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. @@ -162,11 +164,34 @@ class SendAudio(BaseClient): file = None try: - if os.path.exists(audio): + if isinstance(audio, str): + if os.path.isfile(audio): + thumb = None if thumb is None else await self.save_file(thumb) + file = await self.save_file(audio, progress=progress, progress_args=progress_args) + media = types.InputMediaUploadedDocument( + mime_type=self.guess_mime_type(audio) or "audio/mpeg", + file=file, + thumb=thumb, + attributes=[ + types.DocumentAttributeAudio( + duration=duration, + performer=performer, + title=title + ), + types.DocumentAttributeFilename(file_name=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 await self.save_file(thumb) file = await self.save_file(audio, progress=progress, progress_args=progress_args) media = types.InputMediaUploadedDocument( - mime_type=self.guess_mime_type(audio) or "audio/mpeg", + mime_type=self.guess_mime_type(audio.name) or "audio/mpeg", file=file, thumb=thumb, attributes=[ @@ -175,15 +200,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 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 f2b268f1..4beeb800 100644 --- a/pyrogram/client/methods/messages/send_document.py +++ b/pyrogram/client/methods/messages/send_document.py @@ -17,7 +17,8 @@ # along with Pyrogram. If not, see . import os -from typing import Union +import re +from typing import Union, BinaryIO import pyrogram from pyrogram.api import functions, types @@ -29,9 +30,9 @@ class SendDocument(BaseClient): async 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, @@ -55,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. @@ -143,23 +145,35 @@ class SendDocument(BaseClient): file = None try: - if os.path.exists(document): + if isinstance(document, str): + if os.path.isfile(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=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 await self.save_file(thumb) file = await 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_media_group.py b/pyrogram/client/methods/messages/send_media_group.py index c9c2406b..7c7552ce 100644 --- a/pyrogram/client/methods/messages/send_media_group.py +++ b/pyrogram/client/methods/messages/send_media_group.py @@ -16,15 +16,14 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -import asyncio import logging import os +import re from typing import Union, List import pyrogram from pyrogram.api import functions, types from pyrogram.client.ext import BaseClient, utils -from pyrogram.errors import FloodWait log = logging.getLogger(__name__) @@ -77,7 +76,7 @@ class SendMediaGroup(BaseClient): for i in media: if isinstance(i, pyrogram.InputMediaPhoto): - if os.path.exists(i.media): + if os.path.isfile(i.media): media = await self.send( functions.messages.UploadMedia( peer=await self.resolve_peer(chat_id), @@ -94,7 +93,7 @@ class SendMediaGroup(BaseClient): file_reference=media.photo.file_reference ) ) - elif i.media.startswith("http"): + elif re.match("^https?://", i.media): media = await self.send( functions.messages.UploadMedia( peer=await self.resolve_peer(chat_id), @@ -114,7 +113,7 @@ class SendMediaGroup(BaseClient): else: media = utils.get_input_media_from_file_id(i.media, i.file_ref, 2) elif isinstance(i, pyrogram.InputMediaVideo): - if os.path.exists(i.media): + if os.path.isfile(i.media): media = await self.send( functions.messages.UploadMedia( peer=await self.resolve_peer(chat_id), @@ -142,7 +141,7 @@ class SendMediaGroup(BaseClient): file_reference=media.document.file_reference ) ) - elif i.media.startswith("http"): + elif re.match("^https?://", i.media): media = await self.send( functions.messages.UploadMedia( peer=await self.resolve_peer(chat_id), diff --git a/pyrogram/client/methods/messages/send_photo.py b/pyrogram/client/methods/messages/send_photo.py index ed84a83f..7c2c194c 100644 --- a/pyrogram/client/methods/messages/send_photo.py +++ b/pyrogram/client/methods/messages/send_photo.py @@ -17,7 +17,8 @@ # along with Pyrogram. If not, see . import os -from typing import Union +import re +from typing import Union, BinaryIO import pyrogram from pyrogram.api import functions, types @@ -29,7 +30,7 @@ class SendPhoto(BaseClient): async 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, @@ -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`` | ``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. @@ -137,19 +139,26 @@ class SendPhoto(BaseClient): file = None try: - if os.path.exists(photo): + if isinstance(photo, str): + if os.path.isfile(photo): + file = await 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 = await 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 b44f9de0..cbad51ee 100644 --- a/pyrogram/client/methods/messages/send_sticker.py +++ b/pyrogram/client/methods/messages/send_sticker.py @@ -17,7 +17,8 @@ # along with Pyrogram. If not, see . import os -from typing import Union +import re +from typing import Union, BinaryIO import pyrogram from pyrogram.api import functions, types @@ -29,7 +30,7 @@ class SendSticker(BaseClient): async 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, @@ -51,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. @@ -113,21 +115,31 @@ class SendSticker(BaseClient): file = None try: - if os.path.exists(sticker): + if isinstance(sticker, str): + if os.path.isfile(sticker): + file = await 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 = await 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 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 4c8bd2fc..76682327 100644 --- a/pyrogram/client/methods/messages/send_video.py +++ b/pyrogram/client/methods/messages/send_video.py @@ -17,7 +17,8 @@ # along with Pyrogram. If not, see . import os -from typing import Union +import re +from typing import Union, BinaryIO import pyrogram from pyrogram.api import functions, types @@ -29,14 +30,14 @@ class SendVideo(BaseClient): async 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, @@ -59,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. @@ -88,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. @@ -160,11 +162,35 @@ class SendVideo(BaseClient): file = None try: - if os.path.exists(video): + if isinstance(video, str): + if os.path.isfile(video): + thumb = None if thumb is None else await self.save_file(thumb) + file = await 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 await self.save_file(thumb) file = await 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 8a2e7567..7b47daf3 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): async 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.exists(video_note): + if isinstance(video_note, str): + if os.path.isfile(video_note): + thumb = None if thumb is None else await self.save_file(thumb) + file = await self.save_file(video_note, progress=progress, progress_args=progress_args) + media = types.InputMediaUploadedDocument( + mime_type=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 await self.save_file(thumb) file = await 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 d71e3a89..98221e8d 100644 --- a/pyrogram/client/methods/messages/send_voice.py +++ b/pyrogram/client/methods/messages/send_voice.py @@ -17,7 +17,8 @@ # along with Pyrogram. If not, see . import os -from typing import Union +import re +from typing import Union, BinaryIO import pyrogram from pyrogram.api import functions, types @@ -29,7 +30,7 @@ class SendVoice(BaseClient): async 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, @@ -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`` | ``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. @@ -132,10 +134,29 @@ class SendVoice(BaseClient): file = None try: - if os.path.exists(voice): + if isinstance(voice, str): + if os.path.isfile(voice): + file = await 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 = await 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( @@ -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: