Add progress and progress_args parameters to Client.send_media_group and Message.reply_media_group

Signed-off-by: Ling-ex <nekochan@rizkiofficial.com>
This commit is contained in:
Ling-ex 2025-04-24 20:19:32 +00:00 committed by wulan17
parent 1b6d86ea77
commit 04c25b760f
No known key found for this signature in database
GPG key ID: 737814D4B5FF0420
2 changed files with 158 additions and 89 deletions

View file

@ -22,7 +22,12 @@ import os
import re
from datetime import datetime
from pymediainfo import MediaInfo
from typing import Union, List, Optional
from typing import (
Union,
List,
Optional,
Callable,
)
import pyrogram
from pyrogram import enums
@ -35,7 +40,6 @@ log = logging.getLogger(__name__)
class SendMediaGroup:
# TODO: Add progress parameter
async def send_media_group(
self: "pyrogram.Client",
chat_id: Union[int, str],
@ -59,7 +63,9 @@ class SendMediaGroup:
protect_content: bool = None,
allow_paid_broadcast: bool = None,
message_effect_id: int = None,
invert_media: bool = None
invert_media: bool = None,
progress: Callable = None,
progress_args: tuple = (),
) -> List["types.Message"]:
"""Send a group of photos or videos as an album.
@ -89,7 +95,7 @@ class SendMediaGroup:
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
reply_to_story_id (``int``, *optional*):
Unique identifier for the target story.
@ -126,6 +132,28 @@ class SendMediaGroup:
invert_media (``bool``, *optional*):
Inverts the position of the media and caption.
progress (``Callable``, *optional*):
Pass a callback function to view the file transmission progress.
The function must take *(current, total)* as positional arguments (look at Other Parameters below for a
detailed description) and will be called back each time a new file chunk has been successfully
transmitted.
progress_args (``tuple``, *optional*):
Extra custom arguments for the progress callback function.
You can pass anything you need to be available in the progress callback scope; for example, a Message
object or a Client instance in order to edit the message with the updated progress status.
Other Parameters:
current (``int``):
The amount of bytes transmitted so far.
total (``int``):
The total 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:
List of :obj:`~pyrogram.types.Message`: On success, a list of the sent messages is returned.
@ -154,21 +182,22 @@ class SendMediaGroup:
reply_to_chat_id=reply_to_chat_id,
quote_text=quote_text,
quote_entities=quote_entities,
parse_mode=parse_mode
parse_mode=parse_mode,
)
for i in media:
if isinstance(i, types.InputMediaPhoto):
if isinstance(i.media, str):
if os.path.isfile(i.media):
file = await self.save_file(i.media, progress=progress, progress_args=progress_args)
media = await self.invoke(
raw.functions.messages.UploadMedia(
peer=await self.resolve_peer(chat_id),
media=raw.types.InputMediaUploadedPhoto(
file=await self.save_file(i.media),
spoiler=i.has_spoiler
)
)
file=file,
spoiler=i.has_spoiler,
),
),
)
media = raw.types.InputMediaPhoto(
@ -177,7 +206,7 @@ class SendMediaGroup:
access_hash=media.photo.access_hash,
file_reference=media.photo.file_reference
),
spoiler=i.has_spoiler
spoiler=i.has_spoiler,
)
elif re.match("^https?://", i.media):
media = await self.invoke(
@ -185,9 +214,9 @@ class SendMediaGroup:
peer=await self.resolve_peer(chat_id),
media=raw.types.InputMediaPhotoExternal(
url=i.media,
spoiler=i.has_spoiler
)
)
spoiler=i.has_spoiler,
),
),
)
media = raw.types.InputMediaPhoto(
@ -196,19 +225,20 @@ class SendMediaGroup:
access_hash=media.photo.access_hash,
file_reference=media.photo.file_reference
),
spoiler=i.has_spoiler
spoiler=i.has_spoiler,
)
else:
media = utils.get_input_media_from_file_id(i.media, FileType.PHOTO)
else:
file = await self.save_file(i.media, progress=progress, progress_args=progress_args)
media = await self.invoke(
raw.functions.messages.UploadMedia(
peer=await self.resolve_peer(chat_id),
media=raw.types.InputMediaUploadedPhoto(
file=await self.save_file(i.media),
spoiler=i.has_spoiler
)
)
file=file,
spoiler=i.has_spoiler,
),
),
)
media = raw.types.InputMediaPhoto(
@ -217,7 +247,7 @@ class SendMediaGroup:
access_hash=media.photo.access_hash,
file_reference=media.photo.file_reference
),
spoiler=i.has_spoiler
spoiler=i.has_spoiler,
)
elif (
isinstance(i, types.InputMediaVideo)
@ -241,22 +271,25 @@ class SendMediaGroup:
w=i.width,
h=i.height
),
raw.types.DocumentAttributeFilename(file_name=os.path.basename(i.media))
raw.types.DocumentAttributeFilename(file_name=os.path.basename(i.media)),
]
if is_animation:
attributes.append(raw.types.DocumentAttributeAnimated())
thumb = await self.save_file(i.thumb)
file = await self.save_file(i.media, progress=progress, progress_args=progress_args)
media = await self.invoke(
raw.functions.messages.UploadMedia(
peer=await self.resolve_peer(chat_id),
media=raw.types.InputMediaUploadedDocument(
file=await self.save_file(i.media),
thumb=await self.save_file(i.thumb),
file=file,
thumb=thumb,
spoiler=i.has_spoiler,
mime_type=self.guess_mime_type(i.media) or "video/mp4",
nosound_video=is_animation,
attributes=attributes
)
)
attributes=attributes,
),
),
)
media = raw.types.InputMediaDocument(
@ -265,7 +298,7 @@ class SendMediaGroup:
access_hash=media.document.access_hash,
file_reference=media.document.file_reference
),
spoiler=i.has_spoiler
spoiler=i.has_spoiler,
)
elif re.match("^https?://", i.media):
media = await self.invoke(
@ -273,9 +306,9 @@ class SendMediaGroup:
peer=await self.resolve_peer(chat_id),
media=raw.types.InputMediaDocumentExternal(
url=i.media,
spoiler=i.has_spoiler
)
)
spoiler=i.has_spoiler,
),
),
)
media = raw.types.InputMediaDocument(
@ -284,17 +317,19 @@ class SendMediaGroup:
access_hash=media.document.access_hash,
file_reference=media.document.file_reference
),
spoiler=i.has_spoiler
spoiler=i.has_spoiler,
)
else:
media = utils.get_input_media_from_file_id(i.media, FileType.VIDEO)
else:
thumb = await self.save_file(i.thumb)
file = await self.save_file(i.media, progress=progress, progress_args=progress_args)
media = await self.invoke(
raw.functions.messages.UploadMedia(
peer=await self.resolve_peer(chat_id),
media=raw.types.InputMediaUploadedDocument(
file=await self.save_file(i.media),
thumb=await self.save_file(i.thumb),
file=file,
thumb=thumb,
spoiler=i.has_spoiler,
mime_type=self.guess_mime_type(getattr(i.media, "name", "video.mp4")) or "video/mp4",
attributes=[
@ -304,10 +339,10 @@ class SendMediaGroup:
w=i.width,
h=i.height
),
raw.types.DocumentAttributeFilename(file_name=getattr(i.media, "name", "video.mp4"))
]
)
)
raw.types.DocumentAttributeFilename(file_name=getattr(i.media, "name", "video.mp4")),
],
),
),
)
media = raw.types.InputMediaDocument(
@ -316,127 +351,135 @@ class SendMediaGroup:
access_hash=media.document.access_hash,
file_reference=media.document.file_reference
),
spoiler=i.has_spoiler
spoiler=i.has_spoiler,
)
elif isinstance(i, types.InputMediaAudio):
if isinstance(i.media, str):
if os.path.isfile(i.media):
thumb = await self.save_file(i.thumb)
file = await self.save_file(i.media, progress=progress, progress_args=progress_args)
media = await self.invoke(
raw.functions.messages.UploadMedia(
peer=await self.resolve_peer(chat_id),
media=raw.types.InputMediaUploadedDocument(
mime_type=self.guess_mime_type(i.media) or "audio/mpeg",
file=await self.save_file(i.media),
thumb=await self.save_file(i.thumb),
file=file,
thumb=thumb,
attributes=[
raw.types.DocumentAttributeAudio(
duration=i.duration,
performer=i.performer,
title=i.title
),
raw.types.DocumentAttributeFilename(file_name=os.path.basename(i.media))
]
)
)
raw.types.DocumentAttributeFilename(file_name=os.path.basename(i.media)),
],
),
),
)
media = raw.types.InputMediaDocument(
id=raw.types.InputDocument(
id=media.document.id,
access_hash=media.document.access_hash,
file_reference=media.document.file_reference
)
file_reference=media.document.file_reference,
),
)
elif re.match("^https?://", i.media):
media = await self.invoke(
raw.functions.messages.UploadMedia(
peer=await self.resolve_peer(chat_id),
media=raw.types.InputMediaDocumentExternal(
url=i.media
)
)
url=i.media,
),
),
)
media = raw.types.InputMediaDocument(
id=raw.types.InputDocument(
id=media.document.id,
access_hash=media.document.access_hash,
file_reference=media.document.file_reference
)
file_reference=media.document.file_reference,
),
)
else:
media = utils.get_input_media_from_file_id(i.media, FileType.AUDIO)
else:
thumb = await self.save_file(i.thumb)
file = await self.save_file(i.media, progress=progress, progress_args=progress_args)
media = await self.invoke(
raw.functions.messages.UploadMedia(
peer=await self.resolve_peer(chat_id),
media=raw.types.InputMediaUploadedDocument(
mime_type=self.guess_mime_type(getattr(i.media, "name", "audio.mp3")) or "audio/mpeg",
file=await self.save_file(i.media),
thumb=await self.save_file(i.thumb),
file=file,
thumb=thumb,
attributes=[
raw.types.DocumentAttributeAudio(
duration=i.duration,
performer=i.performer,
title=i.title
),
raw.types.DocumentAttributeFilename(file_name=getattr(i.media, "name", "audio.mp3"))
]
)
)
raw.types.DocumentAttributeFilename(file_name=getattr(i.media, "name", "audio.mp3")),
],
),
),
)
media = raw.types.InputMediaDocument(
id=raw.types.InputDocument(
id=media.document.id,
access_hash=media.document.access_hash,
file_reference=media.document.file_reference
)
file_reference=media.document.file_reference,
),
)
elif isinstance(i, types.InputMediaDocument):
if isinstance(i.media, str):
if os.path.isfile(i.media):
thumb = await self.save_file(i.thumb)
file = await self.save_file(i.media, progress=progress, progress_args=progress_args)
media = await self.invoke(
raw.functions.messages.UploadMedia(
peer=await self.resolve_peer(chat_id),
media=raw.types.InputMediaUploadedDocument(
mime_type=self.guess_mime_type(i.media) or "application/zip",
file=await self.save_file(i.media),
thumb=await self.save_file(i.thumb),
file=file,
thumb=thumb,
attributes=[
raw.types.DocumentAttributeFilename(file_name=os.path.basename(i.media))
]
)
)
raw.types.DocumentAttributeFilename(file_name=os.path.basename(i.media)),
],
),
),
)
media = raw.types.InputMediaDocument(
id=raw.types.InputDocument(
id=media.document.id,
access_hash=media.document.access_hash,
file_reference=media.document.file_reference
)
file_reference=media.document.file_reference,
),
)
elif re.match("^https?://", i.media):
media = await self.invoke(
raw.functions.messages.UploadMedia(
peer=await self.resolve_peer(chat_id),
media=raw.types.InputMediaDocumentExternal(
url=i.media
)
)
url=i.media,
),
),
)
media = raw.types.InputMediaDocument(
id=raw.types.InputDocument(
id=media.document.id,
access_hash=media.document.access_hash,
file_reference=media.document.file_reference
)
file_reference=media.document.file_reference,
),
)
else:
media = utils.get_input_media_from_file_id(i.media, FileType.DOCUMENT)
else:
thumb = await self.save_file(i.thumb)
file = await self.save_file(i.media, progress=progress, progress_args=progress_args)
media = await self.invoke(
raw.functions.messages.UploadMedia(
peer=await self.resolve_peer(chat_id),
@ -444,21 +487,21 @@ class SendMediaGroup:
mime_type=self.guess_mime_type(
getattr(i.media, "name", "file.zip")
) or "application/zip",
file=await self.save_file(i.media),
thumb=await self.save_file(i.thumb),
file=file,
thumb=thumb,
attributes=[
raw.types.DocumentAttributeFilename(file_name=getattr(i.media, "name", "file.zip"))
]
)
)
raw.types.DocumentAttributeFilename(file_name=getattr(i.media, "name", "file.zip")),
],
),
),
)
media = raw.types.InputMediaDocument(
id=raw.types.InputDocument(
id=media.document.id,
access_hash=media.document.access_hash,
file_reference=media.document.file_reference
)
file_reference=media.document.file_reference,
),
)
else:
raise ValueError(f"{i.__class__.__name__} is not a supported type for send_media_group")
@ -467,8 +510,8 @@ class SendMediaGroup:
raw.types.InputSingleMedia(
media=media,
random_id=self.rnd_id(),
**(await utils.parse_text_entities(self, i.caption, i.parse_mode, i.caption_entities))
)
**(await utils.parse_text_entities(self, i.caption, i.parse_mode, i.caption_entities)),
),
)
rpc = raw.functions.messages.SendMultiMedia(
@ -480,20 +523,20 @@ class SendMediaGroup:
noforwards=protect_content,
allow_paid_floodskip=allow_paid_broadcast,
effect=message_effect_id,
invert_media=invert_media
invert_media=invert_media,
)
if business_connection_id is not None:
r = await self.invoke(
raw.functions.InvokeWithBusinessConnection(
connection_id=business_connection_id,
query=rpc
),
sleep_threshold=60
sleep_threshold=60,
)
else:
r = await self.invoke(rpc, sleep_threshold=60)
return await utils.parse_messages(
self,
raw.types.messages.Messages(
@ -505,7 +548,7 @@ class SendMediaGroup:
r.updates
)],
users=r.users,
chats=r.chats
chats=r.chats,
),
business_connection_id=business_connection_id
business_connection_id=business_connection_id,
)

View file

@ -2779,7 +2779,9 @@ class Message(Object, Update):
allow_paid_broadcast: bool = None,
message_effect_id: int = None,
parse_mode: Optional["enums.ParseMode"] = None,
invert_media: bool = None
invert_media: bool = None,
progress: Callable = None,
progress_args: tuple = (),
) -> List["types.Message"]:
"""Bound method *reply_media_group* of :obj:`~pyrogram.types.Message`.
@ -2840,6 +2842,28 @@ class Message(Object, Update):
invert_media (``bool``, *optional*):
Inverts the position of the media and caption.
progress (``Callable``, *optional*):
Pass a callback function to view the file transmission progress.
The function must take *(current, total)* as positional arguments (look at Other Parameters below for a
detailed description) and will be called back each time a new file chunk has been successfully
transmitted.
progress_args (``tuple``, *optional*):
Extra custom arguments for the progress callback function.
You can pass anything you need to be available in the progress callback scope; for example, a Message
object or a Client instance in order to edit the message with the updated progress status.
Other Parameters:
current (``int``):
The amount of bytes transmitted so far.
total (``int``):
The total 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:
On success, a :obj:`~pyrogram.types.Messages` object is returned containing all the
single messages sent.
@ -2878,7 +2902,9 @@ class Message(Object, Update):
quote_entities=quote_entities,
allow_paid_broadcast=allow_paid_broadcast,
message_effect_id=message_effect_id,
invert_media=invert_media
invert_media=invert_media,
progress=progress,
progress_args=progress_args,
)
async def reply_photo(