diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py index 1efb6f06..0e186d85 100644 --- a/pyrogram/client/client.py +++ b/pyrogram/client/client.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 logging import math import os @@ -1231,9 +1231,9 @@ class Client(Methods, BaseClient): temp_file_path = "" final_file_path = "" - path = [None] + try: - data, done, progress, progress_args, out, path, to_file = packet + data, directory, file_name, done, progress, progress_args, path = packet temp_file_path = self.get_file( media_type=data.media_type, @@ -1250,15 +1250,13 @@ class Client(Methods, BaseClient): file_size=data.file_size, is_big=data.is_big, progress=progress, - progress_args=progress_args, - out=out + progress_args=progress_args ) - if to_file: - final_file_path = out.name - else: - final_file_path = '' - if to_file: - out.close() + + if temp_file_path: + final_file_path = os.path.abspath(re.sub("\\\\", "/", os.path.join(directory, file_name))) + os.makedirs(directory, exist_ok=True) + shutil.move(temp_file_path, final_file_path) except Exception as e: log.error(e, exc_info=True) @@ -1715,7 +1713,7 @@ class Client(Methods, BaseClient): def save_file( self, - path: Union[str, io.IOBase], + path: str, file_id: int = None, file_part: int = 0, progress: callable = None, @@ -1767,20 +1765,9 @@ 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 - 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) + file_size = os.path.getsize(path) if file_size == 0: raise ValueError("File size equals to 0 B") @@ -1798,74 +1785,67 @@ class Client(Methods, BaseClient): session.start() try: - fp.seek(part_size * file_part) + with open(path, "rb") as f: + f.seek(part_size * file_part) - while True: - chunk = fp.read(part_size) + 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): + if not chunk: + if not is_big: + md5_sum = "".join([hex(i)[2:].zfill(2) for i in md5_sum.digest()]) break - else: - raise AssertionError("Telegram didn't accept chunk #{} of {}".format(file_part, path)) - if is_missing_part: - return + 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 not is_big: - md5_sum.update(chunk) + if session.send(rpc): + break + else: + raise AssertionError("Telegram didn't accept chunk #{} of {}".format(file_part, path)) - file_part += 1 + if is_missing_part: + return - if progress: - progress(min(file_part * part_size, file_size), file_size, *progress_args) + 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=filename, + name=os.path.basename(path), ) else: return types.InputFile( id=file_id, parts=file_total_parts, - name=filename, + name=os.path.basename(path), md5_checksum=md5_sum ) finally: - if isinstance(path, str): - fp.close() session.stop() def get_file( @@ -1884,8 +1864,7 @@ class Client(Methods, BaseClient): file_size: int, is_big: bool, progress: callable, - progress_args: tuple = (), - out: io.IOBase = None + progress_args: tuple = () ) -> str: with self.media_sessions_lock: session = self.media_sessions.get(dc_id, None) @@ -1971,10 +1950,7 @@ class Client(Methods, BaseClient): limit = 1024 * 1024 offset = 0 file_name = "" - if not out: - f = tempfile.NamedTemporaryFile("wb", delete=False) - else: - f = out + try: r = session.send( functions.upload.GetFile( @@ -1985,37 +1961,36 @@ class Client(Methods, BaseClient): ) if isinstance(r, types.upload.File): - if hasattr(f, "name"): + with tempfile.NamedTemporaryFile("wb", delete=False) as f: file_name = f.name - while True: - chunk = r.bytes + while True: + chunk = r.bytes - if not chunk: - break + if not chunk: + break - f.write(chunk) + f.write(chunk) - offset += limit + offset += limit - if progress: - progress( + if progress: + progress( + min(offset, file_size) + if file_size != 0 + else offset, + file_size, + *progress_args + ) - min(offset, file_size) - if file_size != 0 - else offset, - file_size, - *progress_args + r = session.send( + functions.upload.GetFile( + location=location, + offset=offset, + limit=limit + ) ) - r = session.send( - functions.upload.GetFile( - location=location, - offset=offset, - limit=limit - ) - ) - elif isinstance(r, types.upload.FileCdnRedirect): with self.media_sessions_lock: cdn_session = self.media_sessions.get(r.dc_id, None) @@ -2028,71 +2003,70 @@ class Client(Methods, BaseClient): self.media_sessions[r.dc_id] = cdn_session try: - if hasattr(f, "name"): + with tempfile.NamedTemporaryFile("wb", delete=False) as f: file_name = f.name - while True: - r2 = cdn_session.send( - functions.upload.GetCdnFile( - file_token=r.file_token, - offset=offset, - limit=limit - ) - ) - - if isinstance(r2, types.upload.CdnFileReuploadNeeded): - try: - session.send( - functions.upload.ReuploadCdnFile( - file_token=r.file_token, - request_token=r2.request_token - ) + while True: + r2 = cdn_session.send( + functions.upload.GetCdnFile( + file_token=r.file_token, + offset=offset, + limit=limit ) - except VolumeLocNotFound: + ) + + if isinstance(r2, types.upload.CdnFileReuploadNeeded): + try: + session.send( + functions.upload.ReuploadCdnFile( + file_token=r.file_token, + request_token=r2.request_token + ) + ) + except VolumeLocNotFound: + break + else: + continue + + chunk = r2.bytes + + # https://core.telegram.org/cdn#decrypting-files + decrypted_chunk = AES.ctr256_decrypt( + chunk, + r.encryption_key, + bytearray( + r.encryption_iv[:-4] + + (offset // 16).to_bytes(4, "big") + ) + ) + + hashes = session.send( + functions.upload.GetCdnFileHashes( + file_token=r.file_token, + offset=offset + ) + ) + + # https://core.telegram.org/cdn#verifying-files + for i, h in enumerate(hashes): + cdn_chunk = decrypted_chunk[h.limit * i: h.limit * (i + 1)] + assert h.hash == sha256(cdn_chunk).digest(), "Invalid CDN hash part {}".format(i) + + f.write(decrypted_chunk) + + offset += limit + + if progress: + progress( + min(offset, file_size) + if file_size != 0 + else offset, + file_size, + *progress_args + ) + + if len(chunk) < limit: break - else: - continue - - chunk = r2.bytes - - # https://core.telegram.org/cdn#decrypting-files - decrypted_chunk = AES.ctr256_decrypt( - chunk, - r.encryption_key, - bytearray( - r.encryption_iv[:-4] - + (offset // 16).to_bytes(4, "big") - ) - ) - - hashes = session.send( - functions.upload.GetCdnFileHashes( - file_token=r.file_token, - offset=offset - ) - ) - - # https://core.telegram.org/cdn#verifying-files - for i, h in enumerate(hashes): - cdn_chunk = decrypted_chunk[h.limit * i: h.limit * (i + 1)] - assert h.hash == sha256(cdn_chunk).digest(), "Invalid CDN hash part {}".format(i) - - f.write(decrypted_chunk) - - offset += limit - - if progress: - progress( - - min(offset, file_size) - if file_size != 0 - else offset, - file_size, - *progress_args - ) - - if len(chunk) < limit: - break except Exception as e: raise e except Exception as e: @@ -2100,8 +2074,7 @@ class Client(Methods, BaseClient): log.error(e, exc_info=True) try: - if out: - os.remove(file_name) + os.remove(file_name) except OSError: pass diff --git a/pyrogram/client/methods/messages/download_media.py b/pyrogram/client/methods/messages/download_media.py index 2176e4aa..22054397 100644 --- a/pyrogram/client/methods/messages/download_media.py +++ b/pyrogram/client/methods/messages/download_media.py @@ -17,9 +17,7 @@ # along with Pyrogram. If not, see . import binascii -import io import os -import re import struct import time from datetime import datetime @@ -39,7 +37,6 @@ class DownloadMedia(BaseClient): message: Union["pyrogram.Message", str], file_ref: str = None, file_name: str = DEFAULT_DOWNLOAD_DIR, - out: io.IOBase = None, block: bool = True, progress: callable = None, progress_args: tuple = () @@ -61,9 +58,6 @@ class DownloadMedia(BaseClient): You can also specify a path for downloading files in a custom location: paths that end with "/" are considered directories. All non-existent folders will be created automatically. - out (``io.IOBase``, *optional*): - A custom *file-like object* to be used when downloading file. Overrides file_name - block (``bool``, *optional*): Blocks the code execution until the file has been downloaded. Defaults to True. @@ -244,13 +238,6 @@ class DownloadMedia(BaseClient): extension ) - if not out: - out = open(os.path.abspath(re.sub("\\\\", "/", os.path.join(directory, file_name))), 'wb') - os.makedirs(directory, exist_ok=True) - to_file = True - else: - to_file = False - self.download_queue.put((data, done, progress, progress_args, out, path, to_file)) # Cast to string because Path objects aren't supported by Python 3.5 self.download_queue.put((data, str(directory), str(file_name), done, progress, progress_args, path)) diff --git a/pyrogram/client/methods/messages/send_animated_sticker.py b/pyrogram/client/methods/messages/send_animated_sticker.py deleted file mode 100644 index b2959394..00000000 --- a/pyrogram/client/methods/messages/send_animated_sticker.py +++ /dev/null @@ -1,153 +0,0 @@ -# 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 f8078a7c..288ed04e 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,7 +29,6 @@ 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 = "", @@ -60,13 +59,11 @@ 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``| file-like object): + animation (``str``): 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. @@ -166,36 +163,11 @@ class SendAnimation(BaseClient): file = None try: - 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"): + 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.name) or "video/mp4", + mime_type=self.guess_mime_type(animation) or "video/mp4", file=file, thumb=thumb, attributes=[ @@ -205,10 +177,17 @@ class SendAnimation(BaseClient): w=width, h=height ), - types.DocumentAttributeFilename(file_name=animation.name), + 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) + 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 0ff588d8..e271d96c 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,7 +29,6 @@ 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 = "", @@ -61,12 +60,11 @@ 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``, file-like object): + audio (``str``): Audio file to send. Pass a file_id as string to send an audio file that exists on the Telegram servers, pass an HTTP URL as a string for Telegram to get an audio file from the Internet, or pass a file path as string to upload a new audio file that exists on your local machine. - pass a readable file-like object with .name file_ref (``str``, *optional*): A valid file reference obtained by a recently fetched media message. @@ -165,34 +163,11 @@ class SendAudio(BaseClient): file = None try: - 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"): + 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.name) or "audio/mpeg", + mime_type=self.guess_mime_type(audio) or "audio/mpeg", file=file, thumb=thumb, attributes=[ @@ -201,9 +176,15 @@ class SendAudio(BaseClient): performer=performer, title=title ), - types.DocumentAttributeFilename(file_name=os.path.basename(audio.name)) + 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) while True: try: diff --git a/pyrogram/client/methods/messages/send_document.py b/pyrogram/client/methods/messages/send_document.py index be864b4b..24a754f0 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,7 +29,6 @@ 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, @@ -56,13 +55,11 @@ 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`` | file-like object): + document (``str``): File to send. Pass a file_id as string to send a file that exists on the Telegram servers, pass an HTTP URL as a string for Telegram to get a file from the Internet, or pass a file path as string to upload a new file that exists on your local machine. - pass a readable file-like object with .name - file_ref (``str``, *optional*): A valid file reference obtained by a recently fetched media message. @@ -146,35 +143,23 @@ class SendDocument(BaseClient): file = None try: - 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: + 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.name) or "application/zip", + mime_type=self.guess_mime_type(document) or "application/zip", file=file, thumb=thumb, attributes=[ - types.DocumentAttributeFilename(file_name=document.name) + 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) while True: try: diff --git a/pyrogram/client/methods/messages/send_photo.py b/pyrogram/client/methods/messages/send_photo.py index 7877c986..4d6a18a3 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,7 +29,6 @@ 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 = "", @@ -55,12 +54,11 @@ 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`` | file-like object): + photo (``str``): 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. @@ -139,26 +137,19 @@ class SendPhoto(BaseClient): file = None try: - 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"): + 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) while True: try: diff --git a/pyrogram/client/methods/messages/send_sticker.py b/pyrogram/client/methods/messages/send_sticker.py index 60b8609e..76a42d3d 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,7 +29,6 @@ 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, @@ -52,12 +51,11 @@ 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`` | file-like object): + sticker (``str``): 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 a readable file-like object with .name file_ref (``str``, *optional*): A valid file reference obtained by a recently fetched media message. @@ -115,31 +113,21 @@ class SendSticker(BaseClient): file = None try: - 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"): + 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.name) or "image/webp", + mime_type=self.guess_mime_type(sticker) or "image/webp", file=file, attributes=[ - types.DocumentAttributeFilename(file_name=sticker.name) + 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) while True: try: diff --git a/pyrogram/client/methods/messages/send_video.py b/pyrogram/client/methods/messages/send_video.py index 458d5148..fc58aa98 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,7 +29,6 @@ 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 = "", @@ -60,12 +59,11 @@ 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`` | file-like object): + video (``str``): 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 a readable file-like object with .name file_ref (``str``, *optional*): A valid file reference obtained by a recently fetched media message. @@ -162,35 +160,11 @@ class SendVideo(BaseClient): file = None try: - 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"): + 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.name) or "video/mp4", + mime_type=self.guess_mime_type(video) or "video/mp4", file=file, thumb=thumb, attributes=[ @@ -200,9 +174,15 @@ class SendVideo(BaseClient): w=width, h=height ), - types.DocumentAttributeFilename(file_name=video.name) + 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) while True: try: diff --git a/pyrogram/client/methods/messages/send_video_note.py b/pyrogram/client/methods/messages/send_video_note.py index a160567d..64bde11b 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,7 +29,6 @@ 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, @@ -55,12 +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``, file-like object): + video_note (``str``): 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. @@ -130,30 +128,11 @@ class SendVideoNote(BaseClient): file = None try: - 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"): + 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.name) or "video/mp4", + mime_type=self.guess_mime_type(video_note) or "video/mp4", file=file, thumb=thumb, attributes=[ @@ -165,6 +144,8 @@ 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 e4d0e352..753e3806 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,7 +29,6 @@ class SendVoice(BaseClient): def send_voice( self, chat_id: Union[int, str], - voice: Union[str, io.IOBase], voice: str, file_ref=None, caption: str = "", @@ -55,12 +54,11 @@ 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``, file-like object): + voice (``str``): Audio file to send. Pass a file_id as string to send an audio that exists on the Telegram servers, pass an HTTP URL as a string for Telegram to get an audio from the Internet, or pass a file path as string to upload a new audio that exists on your local machine. - pass a readable file-like object with .name file_ref (``str``, *optional*): A valid file reference obtained by a recently fetched media message. @@ -134,29 +132,10 @@ class SendVoice(BaseClient): file = None try: - 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"): + 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.name) or "audio/mpeg", + mime_type=self.guess_mime_type(voice) or "audio/mpeg", file=file, attributes=[ types.DocumentAttributeAudio( @@ -165,6 +144,12 @@ 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: diff --git a/pyrogram/client/types/messages_and_media/message.py b/pyrogram/client/types/messages_and_media/message.py index cff8c578..215f86d0 100644 --- a/pyrogram/client/types/messages_and_media/message.py +++ b/pyrogram/client/types/messages_and_media/message.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 + from functools import partial from typing import List, Match, Union @@ -2964,7 +2964,7 @@ class Message(Object, Update): chat_id=message.chat.id, message_id=message_id, ) - + Example: .. code-block:: python @@ -2985,7 +2985,6 @@ class Message(Object, Update): def download( self, file_name: str = "", - out: io.IOBase = None, block: bool = True, progress: callable = None, progress_args: tuple = () @@ -3010,9 +3009,6 @@ class Message(Object, Update): You can also specify a path for downloading files in a custom location: paths that end with "/" are considered directories. All non-existent folders will be created automatically. - out (``io.IOBase``, *optional*): - A custom *file-like object* to be used when downloading file. Overrides file_name - block (``bool``, *optional*): Blocks the code execution until the file has been downloaded. Defaults to True. @@ -3049,7 +3045,6 @@ class Message(Object, Update): return self._client.download_media( message=self, file_name=file_name, - out=out, block=block, progress=progress, progress_args=progress_args, @@ -3079,7 +3074,7 @@ class Message(Object, Update): Parameters: option (``int``): Index of the poll option you want to vote for (0 to 9). - + Returns: :obj:`Poll`: On success, the poll with the chosen option is returned.