diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index e3ffae3897..2416cfa767 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -321,6 +321,7 @@ def get_title_list(s: str) -> list: send_dice send_document send_location + send_paid_media send_media_group send_message send_photo @@ -515,6 +516,17 @@ def get_title_list(s: str) -> list: InputPhoneContact LinkPreviewOptions """, + input_paid_media=""" + Input Paid Media + InputPaidMedia + InputPaidMediaPhoto + InputPaidMediaVideo + PaidMediaInfo + PaidMedia + PaidMediaPreview + PaidMediaPhoto + PaidMediaVideo + """, input_message_content=""" InputMessageContent ExternalReplyInfo diff --git a/compiler/docs/template/types.rst b/compiler/docs/template/types.rst index ebebe0780d..7fe8f57d73 100644 --- a/compiler/docs/template/types.rst +++ b/compiler/docs/template/types.rst @@ -86,6 +86,19 @@ Input Media {input_media} +Input Paid Media +----------- + +.. autosummary:: + :nosignatures: + + {input_paid_media} + +.. toctree:: + :hidden: + + {input_paid_media} + Inline Mode ----------- diff --git a/docs/source/releases/changes-in-this-fork.rst b/docs/source/releases/changes-in-this-fork.rst index 57a9e9038b..75d9ee0cae 100644 --- a/docs/source/releases/changes-in-this-fork.rst +++ b/docs/source/releases/changes-in-this-fork.rst @@ -14,6 +14,9 @@ If you found any issue or have any suggestions, feel free to make `an issue "types.Message": """Copy messages of any kind. + Service messages, paid media messages, giveaway messages, giveaway winners messages, and invoice messages can't be copied. A quiz poll can be copied only if the value of the field ``correct_option_id`` is known to the bot. + The method is analogous to the method :meth:`~Client.forward_messages`, but the copied message doesn't have a link to the original message. diff --git a/pyrogram/methods/messages/send_paid_media.py b/pyrogram/methods/messages/send_paid_media.py new file mode 100644 index 0000000000..f0f3134510 --- /dev/null +++ b/pyrogram/methods/messages/send_paid_media.py @@ -0,0 +1,274 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# 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 os +import re + +from datetime import datetime +from typing import Union, List, Optional + +import pyrogram +from pyrogram import enums, raw, types, utils +from pyrogram.file_id import FileType + + +class SendPaidMedia: + async def send_paid_media( + self: "pyrogram.Client", + chat_id: Union[int, str], + star_count: int, + media: List[Union[ + "types.InputPaidMediaPhoto", + "types.InputPaidMediaVideo" + ]], + caption: str = "", + parse_mode: Optional["enums.ParseMode"] = None, + caption_entities: List["types.MessageEntity"] = None, + show_caption_above_media: bool = None, + disable_notification: bool = None, + protect_content: bool = None, + reply_parameters: "types.ReplyParameters" = None, + reply_markup: Union[ + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" + ] = None, + schedule_date: datetime = None + ) -> "types.Message": + """Use this method to send paid media to channel chats. + + .. include:: /_includes/usable-by/users-bots.rst + + Parameters: + chat_id (``int`` | ``str``): + Unique identifier for the target chat or username of the target channel (in the format @channelusername). + + star_count (``int``): + The number of Telegram Stars that must be paid to buy access to the media. + + media (List of :obj:`~pyrogram.types.InputPaidMedia`): + A list describing the media to be sent; up to 10 items. + + caption (``str``, *optional*): + Media caption, 0-1024 characters after entities parsing. + + parse_mode (:obj:`~pyrogram.enums.ParseMode`, *optional*): + By default, texts are parsed using both Markdown and HTML styles. + You can combine both syntaxes together. + + caption_entities (List of :obj:`~pyrogram.types.MessageEntity`): + List of special entities that appear in the caption, which can be specified instead of *parse_mode*. + + show_caption_above_media (``bool``, *optional*): + Pass True, if the caption must be shown above the message media. + + disable_notification (``bool``, *optional*): + Sends the message silently. Users will receive a notification with no sound. + + protect_content (``bool``, *optional*): + Protects the contents of the sent message from forwarding and saving. + + reply_parameters (:obj:`~pyrogram.types.ReplyParameters`, *optional*): + Description of the message to reply to + + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.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. + + schedule_date (:obj:`~datetime.datetime`, *optional*): + Date when the message will be automatically sent. Pass a :obj:`~datetime.datetime` object. + + Returns: + :obj:`~pyrogram.types.Message`: On success, the sent message is returned. + + """ + multi_media = [] + + peer = await self.resolve_peer(chat_id) + for i in media: + if isinstance(i, types.InputPaidMediaPhoto): + if isinstance(i.media, str): + if os.path.isfile(i.media): + 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) + ) + ) + ) + + media = raw.types.InputMediaPhoto( + id=raw.types.InputPhoto( + id=media.photo.id, + access_hash=media.photo.access_hash, + file_reference=media.photo.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.InputMediaPhotoExternal( + url=i.media + ) + ) + ) + + media = raw.types.InputMediaPhoto( + id=raw.types.InputPhoto( + id=media.photo.id, + access_hash=media.photo.access_hash, + file_reference=media.photo.file_reference + ) + ) + else: + media = utils.get_input_media_from_file_id(i.media, FileType.PHOTO) + else: + 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) + ) + ) + ) + + media = raw.types.InputMediaPhoto( + id=raw.types.InputPhoto( + id=media.photo.id, + access_hash=media.photo.access_hash, + file_reference=media.photo.file_reference + ) + ) + elif ( + isinstance(i, types.InputPaidMediaVideo) + ): + if isinstance(i.media, str): + if os.path.isfile(i.media): + attributes = [ + raw.types.DocumentAttributeVideo( + supports_streaming=i.supports_streaming or None, + duration=i.duration, + w=i.width, + h=i.height + ), + raw.types.DocumentAttributeFilename(file_name=os.path.basename(i.media)) + ] + 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.thumbnail), + mime_type=self.guess_mime_type(i.media) or "video/mp4", + nosound_video=True, + attributes=attributes + ) + ) + ) + + media = raw.types.InputMediaDocument( + id=raw.types.InputDocument( + id=media.document.id, + access_hash=media.document.access_hash, + 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 + ) + ) + ) + + media = raw.types.InputMediaDocument( + id=raw.types.InputDocument( + id=media.document.id, + access_hash=media.document.access_hash, + file_reference=media.document.file_reference + ) + ) + else: + media = utils.get_input_media_from_file_id(i.media, FileType.VIDEO) + else: + 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.thumbnail), + mime_type=self.guess_mime_type(getattr(i.media, "name", "video.mp4")) or "video/mp4", + attributes=[ + raw.types.DocumentAttributeVideo( + supports_streaming=i.supports_streaming or None, + duration=i.duration, + w=i.width, + h=i.height + ), + raw.types.DocumentAttributeFilename(file_name=getattr(i.media, "name", "video.mp4")) + ] + ) + ) + ) + + media = raw.types.InputMediaDocument( + id=raw.types.InputDocument( + id=media.document.id, + access_hash=media.document.access_hash, + file_reference=media.document.file_reference + ) + ) + else: + raise ValueError(f"{i.__class__.__name__} is not a supported type for send_paid_media") + multi_media.append(media) + + rpc = raw.functions.messages.SendMedia( + peer=await self.resolve_peer(chat_id), + media=raw.types.InputMediaPaidMedia( + stars_amount=star_count, + extended_media=multi_media + ), + silent=disable_notification or None, + random_id=self.rnd_id(), + schedule_date=utils.datetime_to_timestamp(schedule_date), + noforwards=protect_content, + invert_media=show_caption_above_media, + **await utils.parse_text_entities(self, caption, parse_mode, caption_entities) + ) + r = await self.invoke(rpc, sleep_threshold=60) + for i in r.updates: + if isinstance( + i, + ( + raw.types.UpdateNewMessage, + raw.types.UpdateNewChannelMessage, + raw.types.UpdateNewScheduledMessage + ) + ): + return await types.Message._parse( + self, i.message, + {i.id: i for i in r.users}, + {i.id: i for i in r.chats}, + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage), + replies=self.fetch_replies + ) diff --git a/pyrogram/types/__init__.py b/pyrogram/types/__init__.py index 059d37fb90..849e32528d 100644 --- a/pyrogram/types/__init__.py +++ b/pyrogram/types/__init__.py @@ -24,6 +24,7 @@ from .chat_topics import * from .inline_mode import * from .input_media import * +from .input_paid_media import * from .input_message_content import * from .messages_and_media import * from .message_origin import * diff --git a/pyrogram/types/input_message_content/external_reply_info.py b/pyrogram/types/input_message_content/external_reply_info.py index 8651dd0b4a..8a69f3270b 100644 --- a/pyrogram/types/input_message_content/external_reply_info.py +++ b/pyrogram/types/input_message_content/external_reply_info.py @@ -49,6 +49,9 @@ class ExternalReplyInfo(Object): document (:obj:`~pyrogram.types.Document`, *optional*): Message is a general file, information about the file. + paid_media (:obj:`~pyrogram.types.PaidMediaInfo`, *optional*): + Message contains paid media; information about the paid media. + photo (:obj:`~pyrogram.types.Photo`, *optional*): Message is a photo, information about the photo. @@ -109,6 +112,7 @@ def __init__( animation: "types.Animation" = None, audio: "types.Audio" = None, document: "types.Document" = None, + paid_media: "types.PaidMediaInfo" = None, photo: "types.Photo" = None, sticker: "types.Sticker" = None, story: "types.Story" = None, @@ -135,6 +139,7 @@ def __init__( self.animation = animation self.audio = audio self.document = document + self.paid_media = paid_media self.photo = photo self.sticker = sticker self.story = story @@ -183,6 +188,7 @@ async def _parse( animation = None audio = None document = None + paid_media = None photo = None sticker = None story = None @@ -302,6 +308,9 @@ async def _parse( elif isinstance(media, raw.types.MessageMediaInvoice): invoice = types.Invoice._parse(client, media) media_type = enums.MessageMediaType.INVOICE + elif isinstance(media, raw.types.MessageMediaPaidMedia): + paid_media = types.PaidMediaInfo._parse(client, media) + media_type = enums.MessageMediaType.PAID_MEDIA return ExternalReplyInfo( origin=origin, @@ -311,6 +320,7 @@ async def _parse( animation=animation, audio=audio, document=document, + paid_media=paid_media, photo=photo, sticker=sticker, story=story, diff --git a/pyrogram/types/input_paid_media/__init__.py b/pyrogram/types/input_paid_media/__init__.py new file mode 100644 index 0000000000..574b78f61c --- /dev/null +++ b/pyrogram/types/input_paid_media/__init__.py @@ -0,0 +1,37 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# 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 . + +from .input_paid_media import InputPaidMedia +from .input_paid_media_photo import InputPaidMediaPhoto +from .input_paid_media_video import InputPaidMediaVideo +from .paid_media_info import PaidMediaInfo +from .paid_media import PaidMedia +from .paid_media_preview import PaidMediaPreview +from .paid_media_photo import PaidMediaPhoto +from .paid_media_video import PaidMediaVideo + +__all__ = [ + "InputPaidMedia", + "InputPaidMediaPhoto", + "InputPaidMediaVideo", + "PaidMediaInfo", + "PaidMedia", + "PaidMediaPreview", + "PaidMediaPhoto", + "PaidMediaVideo", +] diff --git a/pyrogram/types/input_paid_media/input_paid_media.py b/pyrogram/types/input_paid_media/input_paid_media.py new file mode 100644 index 0000000000..f25e64d926 --- /dev/null +++ b/pyrogram/types/input_paid_media/input_paid_media.py @@ -0,0 +1,39 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# 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 . + +from typing import Union, BinaryIO + +from ..object import Object + + +class InputPaidMedia(Object): + """This object describes the paid media to be sent. + + Currently, it can be one of: + + - :obj:`~pyrogram.types.InputMediaPhoto` + - :obj:`~pyrogram.types.InputMediaVideo` + """ + + def __init__( + self, + media: Union[str, BinaryIO] + ): + super().__init__() + + self.media = media diff --git a/pyrogram/types/input_paid_media/input_paid_media_photo.py b/pyrogram/types/input_paid_media/input_paid_media_photo.py new file mode 100644 index 0000000000..765fd13e26 --- /dev/null +++ b/pyrogram/types/input_paid_media/input_paid_media_photo.py @@ -0,0 +1,45 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# 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 . + +from typing import Optional, List, Union, BinaryIO + +from .input_paid_media import InputPaidMedia +from ... import enums + + +class InputPaidMediaPhoto(InputPaidMedia): + """The paid media to send is a photo. + + It is intended to be used with :obj:`~pyrogram.Client.send_paid_media`. + + Parameters: + media (``str`` | ``BinaryIO``): + Photo to send. + Pass a file_id as string to send a photo that exists on the Telegram servers or + 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 or + pass an HTTP URL as a string for Telegram to get a photo from the Internet. + + """ + + def __init__( + self, + media: Union[str, BinaryIO] + ): + super().__init__(media) + diff --git a/pyrogram/types/input_paid_media/input_paid_media_video.py b/pyrogram/types/input_paid_media/input_paid_media_video.py new file mode 100644 index 0000000000..a4e4bce77c --- /dev/null +++ b/pyrogram/types/input_paid_media/input_paid_media_video.py @@ -0,0 +1,73 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# 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 . + +from typing import Optional, List, Union, BinaryIO + +from .input_paid_media import InputPaidMedia +from ... import enums + + +class InputPaidMediaVideo(InputPaidMedia): + """The paid media to send is a video. + + It is intended to be used with :obj:`~pyrogram.Client.send_paid_media`. + + Parameters: + media (``str`` | ``BinaryIO``): + File to send. + Pass a file_id as string to send a video that exists on the Telegram servers or + 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 or + pass an HTTP URL as a string for Telegram to get a video from the Internet. + + thumbnail (``str`` | ``BinaryIO``): + 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. + Thumbnails can't be reused and can be only uploaded as a new file. + + width (``int``, *optional*): + Video width. + + height (``int``, *optional*): + Video height. + + duration (``int``, *optional*): + Video duration. + + supports_streaming (``bool``, *optional*): + Pass True, if the uploaded video is suitable for streaming. + + """ + + def __init__( + self, + media: Union[str, BinaryIO], + thumbnail: Union[str, BinaryIO] = None, + width: int = 0, + height: int = 0, + duration: int = 0, + supports_streaming: bool = True + ): + super().__init__(media) + + self.thumbnail = thumbnail + self.width = width + self.height = height + self.duration = duration + self.supports_streaming = supports_streaming diff --git a/pyrogram/types/input_paid_media/paid_media.py b/pyrogram/types/input_paid_media/paid_media.py new file mode 100644 index 0000000000..f4e5c3b7bf --- /dev/null +++ b/pyrogram/types/input_paid_media/paid_media.py @@ -0,0 +1,94 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# 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 . + +from typing import Union + +import pyrogram +from pyrogram import raw, types + +from ..object import Object + + +class PaidMedia(Object): + """This object describes paid media. + + Currently, it can be one of: + + - :obj:`~pyrogram.types.PaidMediaPreview` + - :obj:`~pyrogram.types.PaidMediaPhoto` + - :obj:`~pyrogram.types.PaidMediaVideo` + """ + + def __init__( + self + ): + super().__init__() + + + @staticmethod + def _parse( + client: "pyrogram.Client", + extended_media: Union[ + "raw.types.MessageExtendedMediaPreview", + "raw.types.MessageExtendedMedia" + ] + ) -> "PaidMedia": + if isinstance(extended_media, raw.types.MessageExtendedMediaPreview): + return types.PaidMediaPreview( + width=getattr(extended_media, "w", None), + height=getattr(extended_media, "h", None), + duration=getattr(extended_media, "video_duration", None), + minithumbnail=types.StrippedThumbnail( + client=client, + data=extended_media.thumb + ) if getattr(extended_media, "thumb", None) else None + ) + if isinstance(extended_media, raw.types.MessageExtendedMedia): + media = extended_media.media + + has_media_spoiler = getattr(media, "spoiler", None) + ttl_seconds = getattr(media, "ttl_seconds", None) + + if isinstance(media, raw.types.MessageMediaPhoto): + photo = types.Photo._parse(client, media.photo, ttl_seconds, has_media_spoiler) + + return types.PaidMediaPhoto( + photo=photo + ) + + if isinstance(media, raw.types.MessageMediaDocument): + doc = media.document + + if isinstance(doc, raw.types.Document): + attributes = {type(i): i for i in doc.attributes} + + file_name = getattr( + attributes.get( + raw.types.DocumentAttributeFilename, None + ), "file_name", None + ) + + if raw.types.DocumentAttributeVideo in attributes: + video_attributes = attributes[raw.types.DocumentAttributeVideo] + + if not video_attributes.round_message: + video = types.Video._parse(client, doc, video_attributes, file_name, ttl_seconds) + + return types.PaidMediaVideo( + video=video + ) diff --git a/pyrogram/types/input_paid_media/paid_media_info.py b/pyrogram/types/input_paid_media/paid_media_info.py new file mode 100644 index 0000000000..ef2d9d537c --- /dev/null +++ b/pyrogram/types/input_paid_media/paid_media_info.py @@ -0,0 +1,61 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# 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 . + +from typing import List + +import pyrogram +from pyrogram import raw, types +from ..object import Object + + +class PaidMediaInfo(Object): + """Describes the paid media added to a message. + + Parameters: + star_count (``int``): + The number of Telegram Stars that must be paid to buy access to the media. + + paid_media (List of :obj:`~pyrogram.types.PaidMedia`): + Information about the paid media. + + """ + + def __init__( + self, + *, + star_count: str, + paid_media: List["types.PaidMedia"] + ): + super().__init__() + + self.star_count = star_count + self.paid_media = paid_media + + + @staticmethod + def _parse( + client: "pyrogram.Client", + message_paid_media: "raw.types.MessageMediaPaidMedia" + ) -> "PaidMediaInfo": + return PaidMediaInfo( + star_count=message_paid_media.stars_amount, + paid_media=[ + types.PaidMedia._parse(client, em) + for em in message_paid_media.extended_media + ] + ) diff --git a/pyrogram/types/input_paid_media/paid_media_photo.py b/pyrogram/types/input_paid_media/paid_media_photo.py new file mode 100644 index 0000000000..0f06335743 --- /dev/null +++ b/pyrogram/types/input_paid_media/paid_media_photo.py @@ -0,0 +1,42 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# 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 pyrogram +from pyrogram import types + +from ..object import Object +from .paid_media import PaidMedia + + +class PaidMediaPhoto(PaidMedia): + """The paid media is a photo. + + Parameters: + photo (:obj:`~pyrogram.types.Photo`): + The photo. + + """ + + def __init__( + self, + *, + photo: "types.Photo" = None + ): + super().__init__() + + self.photo = photo diff --git a/pyrogram/types/input_paid_media/paid_media_preview.py b/pyrogram/types/input_paid_media/paid_media_preview.py new file mode 100644 index 0000000000..90cc878cc1 --- /dev/null +++ b/pyrogram/types/input_paid_media/paid_media_preview.py @@ -0,0 +1,57 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# 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 pyrogram +from pyrogram import types + +from ..object import Object +from .paid_media import PaidMedia + + +class PaidMediaPreview(PaidMedia): + """The paid media isn't available before the payment. + + Parameters: + width (``int``, *optional*): + Media width as defined by the sender. + + height (``int``, *optional*): + Media height as defined by the sender. + + duration (``int``, *optional*): + Duration of the media in seconds as defined by the sender. + + minithumbnail (:obj:`~pyrogram.types.StrippedThumbnail`, *optional*): + Media minithumbnail; may be None. + + """ + + def __init__( + self, + *, + width: int = None, + height: int = None, + duration: int = None, + minithumbnail: "types.StrippedThumbnail" = None + ): + super().__init__() + + self.width = width + self.height = height + self.duration = duration + self.minithumbnail = minithumbnail diff --git a/pyrogram/types/input_paid_media/paid_media_video.py b/pyrogram/types/input_paid_media/paid_media_video.py new file mode 100644 index 0000000000..cbdfbcf5c5 --- /dev/null +++ b/pyrogram/types/input_paid_media/paid_media_video.py @@ -0,0 +1,42 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# 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 pyrogram +from pyrogram import types + +from ..object import Object +from .paid_media import PaidMedia + + +class PaidMediaVideo(PaidMedia): + """The paid media is a video. + + Parameters: + video (:obj:`~pyrogram.types.Video`): + The video. + + """ + + def __init__( + self, + *, + video: "types.Video" = None + ): + super().__init__() + + self.video = video diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index aea8a46899..d69b1da2ee 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -158,6 +158,9 @@ class Message(Object, Update): document (:obj:`~pyrogram.types.Document`, *optional*): Message is a general file, information about the file. + paid_media (:obj:`~pyrogram.types.PaidMediaInfo`, *optional*): + Message contains paid media; information about the paid media. + photo (:obj:`~pyrogram.types.Photo`, *optional*): Message is a photo, information about the photo. @@ -432,6 +435,7 @@ def __init__( animation: "types.Animation" = None, audio: "types.Audio" = None, document: "types.Document" = None, + paid_media: "types.PaidMediaInfo" = None, photo: "types.Photo" = None, sticker: "types.Sticker" = None, story: "types.Story" = None, @@ -612,6 +616,7 @@ def __init__( self.sender_business_bot = sender_business_bot self.business_connection_id = business_connection_id self.successful_payment = successful_payment + self.paid_media = paid_media self._raw = _raw @staticmethod @@ -1015,6 +1020,7 @@ async def _parse( giveaway = None giveaway_winners = None invoice = None + paid_media = None media = message.media media_type = None @@ -1132,6 +1138,9 @@ async def _parse( elif isinstance(media, raw.types.MessageMediaInvoice): invoice = types.Invoice._parse(client, media) media_type = enums.MessageMediaType.INVOICE + elif isinstance(media, raw.types.MessageMediaPaidMedia): + paid_media = types.PaidMediaInfo._parse(client, media) + media_type = enums.MessageMediaType.PAID_MEDIA else: media = None @@ -1230,7 +1239,8 @@ async def _parse( client=client, link_preview_options=link_preview_options, effect_id=getattr(message, "effect", None), - show_caption_above_media=show_caption_above_media + show_caption_above_media=show_caption_above_media, + paid_media=paid_media ) parsed_message.external_reply = await types.ExternalReplyInfo._parse( diff --git a/pyrogram/types/object.py b/pyrogram/types/object.py index 3253c8ecff..8eaf6aeae3 100644 --- a/pyrogram/types/object.py +++ b/pyrogram/types/object.py @@ -60,6 +60,9 @@ def default(obj: "Object"): if isinstance(obj, datetime): return str(obj) + if not hasattr(obj, "__dict__"): + return obj.__class__.__name__ + return { "_": obj.__class__.__name__, **{ diff --git a/pyrogram/types/user_and_chats/chat_photo.py b/pyrogram/types/user_and_chats/chat_photo.py index 4234b9767b..7d805fc694 100644 --- a/pyrogram/types/user_and_chats/chat_photo.py +++ b/pyrogram/types/user_and_chats/chat_photo.py @@ -121,6 +121,7 @@ def _parse( has_animation=chat_photo.has_video, is_personal=getattr(chat_photo, "personal", False), minithumbnail=types.StrippedThumbnail( + client=client, data=chat_photo.stripped_thumb ) if chat_photo.stripped_thumb else None, client=client