Rework in-memory uploads

This commit is contained in:
Dan 2020-07-09 02:56:09 +02:00
parent de8f784f78
commit b3faf21c95
9 changed files with 260 additions and 126 deletions

View File

@ -16,6 +16,7 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
import io
import logging import logging
import math import math
import os import os
@ -30,7 +31,7 @@ from importlib import import_module, reload
from pathlib import Path from pathlib import Path
from signal import signal, SIGINT, SIGTERM, SIGABRT from signal import signal, SIGINT, SIGTERM, SIGABRT
from threading import Thread from threading import Thread
from typing import Union, List from typing import Union, List, BinaryIO
from pyrogram.api import functions, types from pyrogram.api import functions, types
from pyrogram.api.core import TLObject 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.client.methods.password.utils import compute_check
from pyrogram.crypto import AES from pyrogram.crypto import AES
from pyrogram.errors import ( from pyrogram.errors import (
PhoneMigrate, NetworkMigrate, SessionPasswordNeeded, PhoneMigrate, NetworkMigrate, SessionPasswordNeeded, PeerIdInvalid, VolumeLocNotFound, UserMigrate, ChannelPrivate,
FloodWait, PeerIdInvalid, VolumeLocNotFound, UserMigrate, ChannelPrivate, AuthBytesInvalid, AuthBytesInvalid, BadRequest
BadRequest) )
from pyrogram.session import Auth, Session from pyrogram.session import Auth, Session
from .ext import utils, Syncer, BaseClient, Dispatcher from .ext import utils, Syncer, BaseClient, Dispatcher
from .methods import Methods from .methods import Methods
@ -1713,7 +1714,7 @@ class Client(Methods, BaseClient):
def save_file( def save_file(
self, self,
path: str, path: Union[str, BinaryIO],
file_id: int = None, file_id: int = None,
file_part: int = 0, file_part: int = 0,
progress: callable = None, progress: callable = None,
@ -1767,7 +1768,19 @@ class Client(Methods, BaseClient):
RPCError: In case of a Telegram RPC error. RPCError: In case of a Telegram RPC error.
""" """
part_size = 512 * 1024 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: if file_size == 0:
raise ValueError("File size equals to 0 B") raise ValueError("File size equals to 0 B")
@ -1785,11 +1798,11 @@ class Client(Methods, BaseClient):
session.start() session.start()
try: try:
with open(path, "rb") as f: with fp:
f.seek(part_size * file_part) fp.seek(part_size * file_part)
while True: while True:
chunk = f.read(part_size) chunk = fp.read(part_size)
if not chunk: if not chunk:
if not is_big: if not is_big:
@ -1835,14 +1848,14 @@ class Client(Methods, BaseClient):
return types.InputFileBig( return types.InputFileBig(
id=file_id, id=file_id,
parts=file_total_parts, parts=file_total_parts,
name=os.path.basename(path), name=file_name,
) )
else: else:
return types.InputFile( return types.InputFile(
id=file_id, id=file_id,
parts=file_total_parts, parts=file_total_parts,
name=os.path.basename(path), name=file_name,
md5_checksum=md5_sum md5_checksum=md5_sum
) )
finally: finally:

View File

@ -18,7 +18,7 @@
import os import os
import re import re
from typing import Union from typing import Union, BinaryIO
import pyrogram import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
@ -30,7 +30,7 @@ class SendAnimation(BaseClient):
def send_animation( def send_animation(
self, self,
chat_id: Union[int, str], chat_id: Union[int, str],
animation: str, animation: Union[str, BinaryIO],
file_ref: str = None, file_ref: str = None,
caption: str = "", caption: str = "",
unsave: bool = False, unsave: bool = False,
@ -38,7 +38,7 @@ class SendAnimation(BaseClient):
duration: int = 0, duration: int = 0,
width: int = 0, width: int = 0,
height: int = 0, height: int = 0,
thumb: str = None, thumb: Union[str, BinaryIO] = None,
file_name: str = None, file_name: str = None,
disable_notification: bool = None, disable_notification: bool = None,
reply_to_message_id: int = 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 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). 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. Animation to send.
Pass a file_id as string to send an animation that exists on the Telegram servers, 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 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. 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*): file_ref (``str``, *optional*):
A valid file reference obtained by a recently fetched media message. A valid file reference obtained by a recently fetched media message.
@ -93,7 +94,7 @@ class SendAnimation(BaseClient):
height (``int``, *optional*): height (``int``, *optional*):
Animation height. Animation height.
thumb (``str``, *optional*): thumb (``str`` | ``BinaryIO``, *optional*):
Thumbnail of the animation file sent. Thumbnail of the animation file sent.
The thumbnail should be in JPEG format and less than 200 KB in size. 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. A thumbnail's width and height should not exceed 320 pixels.
@ -164,11 +165,36 @@ class SendAnimation(BaseClient):
file = None file = None
try: 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) thumb = None if thumb is None else self.save_file(thumb)
file = self.save_file(animation, progress=progress, progress_args=progress_args) file = self.save_file(animation, progress=progress, progress_args=progress_args)
media = types.InputMediaUploadedDocument( 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, file=file,
thumb=thumb, thumb=thumb,
attributes=[ attributes=[
@ -178,16 +204,10 @@ class SendAnimation(BaseClient):
w=width, w=width,
h=height h=height
), ),
types.DocumentAttributeFilename(file_name=file_name or os.path.basename(animation)), types.DocumentAttributeFilename(file_name=animation.name),
types.DocumentAttributeAnimated() 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: while True:
try: try:

View File

@ -18,7 +18,7 @@
import os import os
import re import re
from typing import Union from typing import Union, BinaryIO
import pyrogram import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
@ -30,14 +30,14 @@ class SendAudio(BaseClient):
def send_audio( def send_audio(
self, self,
chat_id: Union[int, str], chat_id: Union[int, str],
audio: str, audio: Union[str, BinaryIO],
file_ref: str = None, file_ref: str = None,
caption: str = "", caption: str = "",
parse_mode: Union[str, None] = object, parse_mode: Union[str, None] = object,
duration: int = 0, duration: int = 0,
performer: str = None, performer: str = None,
title: str = None, title: str = None,
thumb: str = None, thumb: Union[str, BinaryIO] = None,
file_name: str = None, file_name: str = None,
disable_notification: bool = None, disable_notification: bool = None,
reply_to_message_id: int = 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 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). 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. Audio file to send.
Pass a file_id as string to send an audio file that exists on the Telegram servers, 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 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. 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*): file_ref (``str``, *optional*):
A valid file reference obtained by a recently fetched media message. A valid file reference obtained by a recently fetched media message.
@ -90,7 +91,7 @@ class SendAudio(BaseClient):
title (``str``, *optional*): title (``str``, *optional*):
Track name. Track name.
thumb (``str``, *optional*): thumb (``str`` | ``BinaryIO``, *optional*):
Thumbnail of the music file album cover. Thumbnail of the music file album cover.
The thumbnail should be in JPEG format and less than 200 KB in size. 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. A thumbnail's width and height should not exceed 320 pixels.
@ -164,11 +165,34 @@ class SendAudio(BaseClient):
file = None file = None
try: 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) thumb = None if thumb is None else self.save_file(thumb)
file = self.save_file(audio, progress=progress, progress_args=progress_args) file = self.save_file(audio, progress=progress, progress_args=progress_args)
media = types.InputMediaUploadedDocument( 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, file=file,
thumb=thumb, thumb=thumb,
attributes=[ attributes=[
@ -177,15 +201,9 @@ class SendAudio(BaseClient):
performer=performer, performer=performer,
title=title 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: while True:
try: try:

View File

@ -18,7 +18,7 @@
import os import os
import re import re
from typing import Union from typing import Union, BinaryIO
import pyrogram import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
@ -30,9 +30,9 @@ class SendDocument(BaseClient):
def send_document( def send_document(
self, self,
chat_id: Union[int, str], chat_id: Union[int, str],
document: str, document: Union[str, BinaryIO],
file_ref: str = None, file_ref: str = None,
thumb: str = None, thumb: Union[str, BinaryIO] = None,
caption: str = "", caption: str = "",
parse_mode: Union[str, None] = object, parse_mode: Union[str, None] = object,
file_name: str = None, 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 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). 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. File to send.
Pass a file_id as string to send a file that exists on the Telegram servers, 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 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. 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*): file_ref (``str``, *optional*):
A valid file reference obtained by a recently fetched media message. 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. 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. Thumbnail of the file sent.
The thumbnail should be in JPEG format and less than 200 KB in size. 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. A thumbnail's width and height should not exceed 320 pixels.
@ -144,23 +145,35 @@ class SendDocument(BaseClient):
file = None file = None
try: 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) thumb = None if thumb is None else self.save_file(thumb)
file = self.save_file(document, progress=progress, progress_args=progress_args) file = self.save_file(document, progress=progress, progress_args=progress_args)
media = types.InputMediaUploadedDocument( 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, file=file,
thumb=thumb, thumb=thumb,
attributes=[ 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: while True:
try: try:

View File

@ -18,7 +18,7 @@
import os import os
import re import re
from typing import Union from typing import Union, BinaryIO
import pyrogram import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
@ -30,7 +30,7 @@ class SendPhoto(BaseClient):
def send_photo( def send_photo(
self, self,
chat_id: Union[int, str], chat_id: Union[int, str],
photo: str, photo: Union[str, BinaryIO],
file_ref: str = None, file_ref: str = None,
caption: str = "", caption: str = "",
parse_mode: Union[str, None] = object, 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 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). 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. Photo to send.
Pass a file_id as string to send a photo that exists on the Telegram servers, 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 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. 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*): file_ref (``str``, *optional*):
A valid file reference obtained by a recently fetched media message. A valid file reference obtained by a recently fetched media message.
@ -138,19 +139,26 @@ class SendPhoto(BaseClient):
file = None file = None
try: 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) file = self.save_file(photo, progress=progress, progress_args=progress_args)
media = types.InputMediaUploadedPhoto( media = types.InputMediaUploadedPhoto(
file=file, file=file,
ttl_seconds=ttl_seconds 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: while True:
try: try:

View File

@ -18,7 +18,7 @@
import os import os
import re import re
from typing import Union from typing import Union, BinaryIO
import pyrogram import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
@ -30,7 +30,7 @@ class SendSticker(BaseClient):
def send_sticker( def send_sticker(
self, self,
chat_id: Union[int, str], chat_id: Union[int, str],
sticker: str, sticker: Union[str, BinaryIO],
file_ref: str = None, file_ref: str = None,
disable_notification: bool = None, disable_notification: bool = None,
reply_to_message_id: int = 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 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). 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. Sticker to send.
Pass a file_id as string to send a sticker that exists on the Telegram servers, 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 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. 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*): file_ref (``str``, *optional*):
A valid file reference obtained by a recently fetched media message. A valid file reference obtained by a recently fetched media message.
@ -114,21 +115,31 @@ class SendSticker(BaseClient):
file = None file = None
try: 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) file = self.save_file(sticker, progress=progress, progress_args=progress_args)
media = types.InputMediaUploadedDocument( 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, file=file,
attributes=[ 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: while True:
try: try:

View File

@ -18,7 +18,7 @@
import os import os
import re import re
from typing import Union from typing import Union, BinaryIO
import pyrogram import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
@ -30,14 +30,14 @@ class SendVideo(BaseClient):
def send_video( def send_video(
self, self,
chat_id: Union[int, str], chat_id: Union[int, str],
video: str, video: Union[str, BinaryIO],
file_ref: str = None, file_ref: str = None,
caption: str = "", caption: str = "",
parse_mode: Union[str, None] = object, parse_mode: Union[str, None] = object,
duration: int = 0, duration: int = 0,
width: int = 0, width: int = 0,
height: int = 0, height: int = 0,
thumb: str = None, thumb: Union[str, BinaryIO] = None,
file_name: str = None, file_name: str = None,
supports_streaming: bool = True, supports_streaming: bool = True,
disable_notification: bool = None, 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 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). 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. Video to send.
Pass a file_id as string to send a video that exists on the Telegram servers, 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 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. 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*): file_ref (``str``, *optional*):
A valid file reference obtained by a recently fetched media message. A valid file reference obtained by a recently fetched media message.
@ -89,7 +90,7 @@ class SendVideo(BaseClient):
height (``int``, *optional*): height (``int``, *optional*):
Video height. Video height.
thumb (``str``, *optional*): thumb (``str`` | ``BinaryIO``, *optional*):
Thumbnail of the video sent. Thumbnail of the video sent.
The thumbnail should be in JPEG format and less than 200 KB in size. 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. A thumbnail's width and height should not exceed 320 pixels.
@ -161,11 +162,35 @@ class SendVideo(BaseClient):
file = None file = None
try: 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) thumb = None if thumb is None else self.save_file(thumb)
file = self.save_file(video, progress=progress, progress_args=progress_args) file = self.save_file(video, progress=progress, progress_args=progress_args)
media = types.InputMediaUploadedDocument( 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, file=file,
thumb=thumb, thumb=thumb,
attributes=[ attributes=[
@ -175,15 +200,9 @@ class SendVideo(BaseClient):
w=width, w=width,
h=height 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: while True:
try: try:

View File

@ -17,7 +17,7 @@
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
import os import os
from typing import Union from typing import Union, BinaryIO
import pyrogram import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
@ -29,11 +29,11 @@ class SendVideoNote(BaseClient):
def send_video_note( def send_video_note(
self, self,
chat_id: Union[int, str], chat_id: Union[int, str],
video_note: str, video_note: Union[str, BinaryIO],
file_ref: str = None, file_ref: str = None,
duration: int = 0, duration: int = 0,
length: int = 1, length: int = 1,
thumb: str = None, thumb: Union[str, BinaryIO] = None,
disable_notification: bool = None, disable_notification: bool = None,
reply_to_message_id: int = None, reply_to_message_id: int = None,
schedule_date: 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 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). 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. 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_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. 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. Sending video notes by a URL is currently unsupported.
file_ref (``str``, *optional*): file_ref (``str``, *optional*):
@ -70,7 +71,7 @@ class SendVideoNote(BaseClient):
length (``int``, *optional*): length (``int``, *optional*):
Video width and height. Video width and height.
thumb (``str``, *optional*): thumb (``str`` | ``BinaryIO``, *optional*):
Thumbnail of the video sent. Thumbnail of the video sent.
The thumbnail should be in JPEG format and less than 200 KB in size. 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. A thumbnail's width and height should not exceed 320 pixels.
@ -128,11 +129,30 @@ class SendVideoNote(BaseClient):
file = None file = None
try: 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) thumb = None if thumb is None else self.save_file(thumb)
file = self.save_file(video_note, progress=progress, progress_args=progress_args) file = self.save_file(video_note, progress=progress, progress_args=progress_args)
media = types.InputMediaUploadedDocument( 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, file=file,
thumb=thumb, thumb=thumb,
attributes=[ attributes=[
@ -144,8 +164,6 @@ class SendVideoNote(BaseClient):
) )
] ]
) )
else:
media = utils.get_input_media_from_file_id(video_note, file_ref, 13)
while True: while True:
try: try:

View File

@ -18,7 +18,7 @@
import os import os
import re import re
from typing import Union from typing import Union, BinaryIO
import pyrogram import pyrogram
from pyrogram.api import functions, types from pyrogram.api import functions, types
@ -30,7 +30,7 @@ class SendVoice(BaseClient):
def send_voice( def send_voice(
self, self,
chat_id: Union[int, str], chat_id: Union[int, str],
voice: str, voice: Union[str, BinaryIO],
file_ref=None, file_ref=None,
caption: str = "", caption: str = "",
parse_mode: Union[str, None] = object, 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 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). 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. Audio file to send.
Pass a file_id as string to send an audio that exists on the Telegram servers, 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 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. 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*): file_ref (``str``, *optional*):
A valid file reference obtained by a recently fetched media message. A valid file reference obtained by a recently fetched media message.
@ -133,10 +134,29 @@ class SendVoice(BaseClient):
file = None file = None
try: 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) file = self.save_file(voice, progress=progress, progress_args=progress_args)
media = types.InputMediaUploadedDocument( 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, file=file,
attributes=[ attributes=[
types.DocumentAttributeAudio( 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: while True:
try: try: