From b670101daceb7288d9066e32bf0e1de7c1c0df19 Mon Sep 17 00:00:00 2001 From: wulan17 Date: Sun, 13 Aug 2023 01:52:24 +0700 Subject: [PATCH] Pyrofork: Add Story Support Signed-off-by: wulan17 Pyrofork: Add Story and StoryViews Signed-off-by: wulan17 Pyrofork: Add get_stories method Signed-off-by: wulan17 Pyrofork: Add StoriesPrivacy Signed-off-by: wulan17 Pyrofork: Add send_story method Signed-off-by: wulan17 Pyrofork: Add edit_story method Signed-off-by: wulan17 Pyrofork: Add delete_story method Signed-off-by: wulan17 Pyrofork: Add export_story_link method Signed-off-by: wulan17 Pyrofork: Add story bound method Signed-off-by: wulan17 --- compiler/docs/compiler.py | 36 + compiler/docs/template/bound-methods.rst | 13 + compiler/docs/template/methods.rst | 13 + compiler/docs/template/types.rst | 13 + docs/source/api/enums/StoriesPrivacy.rst | 8 + docs/source/api/enums/index.rst | 4 +- pyrogram/enums/__init__.py | 4 +- pyrogram/enums/stories_privacy.py | 40 + pyrogram/methods/messages/send_animation.py | 7 + pyrogram/methods/messages/send_audio.py | 7 + .../methods/messages/send_cached_media.py | 7 + pyrogram/methods/messages/send_dice.py | 7 + pyrogram/methods/messages/send_document.py | 7 + pyrogram/methods/messages/send_media_group.py | 7 + pyrogram/methods/messages/send_message.py | 7 + pyrogram/methods/messages/send_photo.py | 7 + pyrogram/methods/messages/send_sticker.py | 7 + pyrogram/methods/messages/send_video.py | 7 + pyrogram/methods/messages/send_video_note.py | 9 +- pyrogram/methods/messages/send_voice.py | 10 + pyrogram/methods/users/__init__.py | 12 +- pyrogram/methods/users/delete_stories.py | 65 + pyrogram/methods/users/edit_story.py | 240 +++ pyrogram/methods/users/export_story_link.py | 66 + pyrogram/methods/users/get_stories.py | 76 + pyrogram/methods/users/send_story.py | 256 +++ .../types/input_message_content/__init__.py | 3 +- .../input_reply_to_story.py | 49 + pyrogram/types/messages_and_media/__init__.py | 6 +- .../messages_and_media/exported_story_link.py | 44 + .../messages_and_media/stories_privacy.py | 47 + pyrogram/types/messages_and_media/story.py | 1638 +++++++++++++++++ .../types/messages_and_media/story_views.py | 50 + 33 files changed, 2766 insertions(+), 6 deletions(-) create mode 100644 docs/source/api/enums/StoriesPrivacy.rst create mode 100644 pyrogram/enums/stories_privacy.py create mode 100644 pyrogram/methods/users/delete_stories.py create mode 100644 pyrogram/methods/users/edit_story.py create mode 100644 pyrogram/methods/users/export_story_link.py create mode 100644 pyrogram/methods/users/get_stories.py create mode 100644 pyrogram/methods/users/send_story.py create mode 100644 pyrogram/types/input_message_content/input_reply_to_story.py create mode 100644 pyrogram/types/messages_and_media/exported_story_link.py create mode 100644 pyrogram/types/messages_and_media/stories_privacy.py create mode 100644 pyrogram/types/messages_and_media/story.py create mode 100644 pyrogram/types/messages_and_media/story_views.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 65544071..b014b164 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -268,6 +268,14 @@ def pyrogram_api(): get_default_emoji_statuses set_emoji_status """, + stories=""" + Stories + delete_stories + edit_story + export_story_link + get_stories + send_story + """, stickers=""" Stickers add_sticker_to_set @@ -450,6 +458,12 @@ def pyrogram_api(): GeneralTopicHidden GeneralTopicUnhidden """, + stories=""" + Stories + Story + StoriesPrivacy + StoryViews + """, bot_keyboards=""" Bot keyboards ReplyKeyboardMarkup @@ -521,6 +535,7 @@ def pyrogram_api(): InputMessageContent InputMessageContent InputReplyToMessage + InputReplyToStory InputTextMessageContent """, authorization=""" @@ -622,6 +637,27 @@ def pyrogram_api(): User.block User.unblock """, + story=""" + Story + Story.delete + Story.edit + Story.edit_animation + Story.edit_caption + Story.edit_photo + Story.edit_privacy + Story.edit_video + Story.export_link + Story.reply_text + Story.reply_animation + Story.reply_audio + Story.reply_cached_media + Story.reply_media_group + Story.reply_photo + Story.reply_sticker + Story.reply_video + Story.reply_video_note + Story.reply_voice + """, callback_query=""" Callback Query CallbackQuery.answer diff --git a/compiler/docs/template/bound-methods.rst b/compiler/docs/template/bound-methods.rst index 02061e00..ff712cdf 100644 --- a/compiler/docs/template/bound-methods.rst +++ b/compiler/docs/template/bound-methods.rst @@ -36,6 +36,19 @@ Message {message_toctree} +Story +----- + +.. hlist:: + :columns: 3 + + {story_hlist} + +.. toctree:: + :hidden: + + {story_toctree} + Chat ---- diff --git a/compiler/docs/template/methods.rst b/compiler/docs/template/methods.rst index 868dd16e..effe19f5 100644 --- a/compiler/docs/template/methods.rst +++ b/compiler/docs/template/methods.rst @@ -60,6 +60,19 @@ Messages {messages} +Stories +------- + +.. autosummary:: + :nosignatures: + + {stories} + +.. toctree:: + :hidden: + + {stories} + Chats ----- diff --git a/compiler/docs/template/types.rst b/compiler/docs/template/types.rst index ea5d58a2..08630cbb 100644 --- a/compiler/docs/template/types.rst +++ b/compiler/docs/template/types.rst @@ -47,6 +47,19 @@ Messages & Media {messages_media} +Stories +------- + +.. autosummary:: + :nosignatures: + + {stories} + +.. toctree:: + :hidden: + + {stories} + Bot keyboards ------------- diff --git a/docs/source/api/enums/StoriesPrivacy.rst b/docs/source/api/enums/StoriesPrivacy.rst new file mode 100644 index 00000000..cc3a1b83 --- /dev/null +++ b/docs/source/api/enums/StoriesPrivacy.rst @@ -0,0 +1,8 @@ +StoriesPrivacy +============== + +.. autoclass:: pyrogram.enums.StoriesPrivacy() + :members: + +.. raw:: html + :file: ./cleanup.html \ No newline at end of file diff --git a/docs/source/api/enums/index.rst b/docs/source/api/enums/index.rst index a73746f2..26065242 100644 --- a/docs/source/api/enums/index.rst +++ b/docs/source/api/enums/index.rst @@ -27,6 +27,7 @@ to apply only a valid value among the expected ones. SentCodeType NextCodeType UserStatus + StoriesPrivacy .. toctree:: :hidden: @@ -44,4 +45,5 @@ to apply only a valid value among the expected ones. PollType SentCodeType NextCodeType - UserStatus \ No newline at end of file + UserStatus + StoriesPrivacy \ No newline at end of file diff --git a/pyrogram/enums/__init__.py b/pyrogram/enums/__init__.py index d19c7044..042fded3 100644 --- a/pyrogram/enums/__init__.py +++ b/pyrogram/enums/__init__.py @@ -29,6 +29,7 @@ from .next_code_type import NextCodeType from .parse_mode import ParseMode from .poll_type import PollType from .sent_code_type import SentCodeType +from .stories_privacy import StoriesPrivacy from .user_status import UserStatus __all__ = [ @@ -44,6 +45,7 @@ __all__ = [ 'NextCodeType', 'ParseMode', 'PollType', - 'SentCodeType', + 'SentCodeType', + "StoriesPrivacy", 'UserStatus' ] diff --git a/pyrogram/enums/stories_privacy.py b/pyrogram/enums/stories_privacy.py new file mode 100644 index 00000000..93e2e984 --- /dev/null +++ b/pyrogram/enums/stories_privacy.py @@ -0,0 +1,40 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2022-present Mayuri-Chan +# +# This file is part of Pyrofork. +# +# Pyrofork 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. +# +# Pyrofork 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 Pyrofork. If not, see . + +from enum import auto + +from .auto_name import AutoName + + +class StoriesPrivacy(AutoName): + """Poll type enumeration used in :obj:`~pyrogram.types.Story`.""" + + PUBLIC = auto() + "Public stories" + + CLOSE_FRIENDS = auto() + "Close_Friends stories" + + CONTACTS = auto() + "Contacts only stories" + + PRIVATE = auto() + "Private stories" + + NO_CONTACTS = auto() + "Hide stories from contacts" diff --git a/pyrogram/methods/messages/send_animation.py b/pyrogram/methods/messages/send_animation.py index 933b4497..bff8593b 100644 --- a/pyrogram/methods/messages/send_animation.py +++ b/pyrogram/methods/messages/send_animation.py @@ -49,6 +49,7 @@ class SendAnimation: disable_notification: bool = None, message_thread_id: int = None, reply_to_message_id: int = None, + reply_to_story_id: int = None, schedule_date: datetime = None, protect_content: bool = None, reply_markup: Union[ @@ -123,6 +124,9 @@ class SendAnimation: 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. schedule_date (:py:obj:`~datetime.datetime`, *optional*): Date when the message will be automatically sent. @@ -184,6 +188,9 @@ class SendAnimation: reply_to = None if reply_to_message_id or message_thread_id: reply_to = types.InputReplyToMessage(reply_to_message_id=reply_to_message_id, message_thread_id=message_thread_id) + if reply_to_story_id: + user_id = await self.resolve_peer(chat_id) + reply_to = types.InputReplyToStory(user_id=user_id, story_id=reply_to_story_id) try: if isinstance(animation, str): diff --git a/pyrogram/methods/messages/send_audio.py b/pyrogram/methods/messages/send_audio.py index 197967e6..a554a1ce 100644 --- a/pyrogram/methods/messages/send_audio.py +++ b/pyrogram/methods/messages/send_audio.py @@ -47,6 +47,7 @@ class SendAudio: disable_notification: bool = None, message_thread_id: int = None, reply_to_message_id: int = None, + reply_to_story_id: int = None, schedule_date: datetime = None, protect_content: bool = None, reply_markup: Union[ @@ -116,6 +117,9 @@ class SendAudio: 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. schedule_date (:py:obj:`~datetime.datetime`, *optional*): Date when the message will be automatically sent. @@ -178,6 +182,9 @@ class SendAudio: reply_to = None if reply_to_message_id or message_thread_id: reply_to = types.InputReplyToMessage(reply_to_message_id=reply_to_message_id, message_thread_id=message_thread_id) + if reply_to_story_id: + user_id = await self.resolve_peer(chat_id) + reply_to = types.InputReplyToStory(user_id=user_id, story_id=reply_to_story_id) try: if isinstance(audio, str): diff --git a/pyrogram/methods/messages/send_cached_media.py b/pyrogram/methods/messages/send_cached_media.py index aacd12f5..28ab1a31 100644 --- a/pyrogram/methods/messages/send_cached_media.py +++ b/pyrogram/methods/messages/send_cached_media.py @@ -38,6 +38,7 @@ class SendCachedMedia: disable_notification: bool = None, message_thread_id: int = None, reply_to_message_id: int = None, + reply_to_story_id: int = None, schedule_date: datetime = None, protect_content: bool = None, reply_markup: Union[ @@ -88,6 +89,9 @@ class SendCachedMedia: 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. schedule_date (:py:obj:`~datetime.datetime`, *optional*): Date when the message will be automatically sent. @@ -111,6 +115,9 @@ class SendCachedMedia: reply_to = None if reply_to_message_id or message_thread_id: reply_to = types.InputReplyToMessage(reply_to_message_id=reply_to_message_id, message_thread_id=message_thread_id) + if reply_to_story_id: + user_id = await self.resolve_peer(chat_id) + reply_to = types.InputReplyToStory(user_id=user_id, story_id=reply_to_story_id) media = utils.get_input_media_from_file_id(file_id) media.spoiler = has_spoiler diff --git a/pyrogram/methods/messages/send_dice.py b/pyrogram/methods/messages/send_dice.py index 5f14cd5d..ecd504b9 100644 --- a/pyrogram/methods/messages/send_dice.py +++ b/pyrogram/methods/messages/send_dice.py @@ -33,6 +33,7 @@ class SendDice: disable_notification: bool = None, message_thread_id: int = None, reply_to_message_id: int = None, + reply_to_story_id: int = None, schedule_date: datetime = None, protect_content: bool = None, reply_markup: Union[ @@ -69,6 +70,9 @@ class SendDice: 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. schedule_date (:py:obj:`~datetime.datetime`, *optional*): Date when the message will be automatically sent. @@ -99,6 +103,9 @@ class SendDice: reply_to = None if reply_to_message_id or message_thread_id: reply_to = types.InputReplyToMessage(reply_to_message_id=reply_to_message_id, message_thread_id=message_thread_id) + if reply_to_story_id: + user_id = await self.resolve_peer(chat_id) + reply_to = types.InputReplyToStory(user_id=user_id, story_id=reply_to_story_id) r = await self.invoke( raw.functions.messages.SendMedia( diff --git a/pyrogram/methods/messages/send_document.py b/pyrogram/methods/messages/send_document.py index fcf17da8..7f4df28d 100644 --- a/pyrogram/methods/messages/send_document.py +++ b/pyrogram/methods/messages/send_document.py @@ -45,6 +45,7 @@ class SendDocument: disable_notification: bool = None, message_thread_id: int = None, reply_to_message_id: int = None, + reply_to_story_id: int = None, schedule_date: datetime = None, protect_content: bool = None, reply_markup: Union[ @@ -108,6 +109,9 @@ class SendDocument: 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. schedule_date (:py:obj:`~datetime.datetime`, *optional*): Date when the message will be automatically sent. @@ -165,6 +169,9 @@ class SendDocument: reply_to = None if reply_to_message_id or message_thread_id: reply_to = types.InputReplyToMessage(reply_to_message_id=reply_to_message_id, message_thread_id=message_thread_id) + if reply_to_story_id: + user_id = await self.resolve_peer(chat_id) + reply_to = types.InputReplyToStory(user_id=user_id, story_id=reply_to_story_id) try: if isinstance(document, str): diff --git a/pyrogram/methods/messages/send_media_group.py b/pyrogram/methods/messages/send_media_group.py index 49eb7721..1270f110 100644 --- a/pyrogram/methods/messages/send_media_group.py +++ b/pyrogram/methods/messages/send_media_group.py @@ -46,6 +46,7 @@ class SendMediaGroup: disable_notification: bool = None, message_thread_id: int = None, reply_to_message_id: int = None, + reply_to_story_id: int = None, schedule_date: datetime = None, protect_content: bool = None, ) -> List["types.Message"]: @@ -72,6 +73,9 @@ 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. schedule_date (:py:obj:`~datetime.datetime`, *optional*): Date when the message will be automatically sent. @@ -101,6 +105,9 @@ class SendMediaGroup: reply_to = None if reply_to_message_id or message_thread_id: reply_to = types.InputReplyToMessage(reply_to_message_id=reply_to_message_id, message_thread_id=message_thread_id) + if reply_to_story_id: + user_id = await self.resolve_peer(chat_id) + reply_to = types.InputReplyToStory(user_id=user_id, story_id=reply_to_story_id) for i in media: if isinstance(i, types.InputMediaPhoto): diff --git a/pyrogram/methods/messages/send_message.py b/pyrogram/methods/messages/send_message.py index ab068078..9f3f4d0b 100644 --- a/pyrogram/methods/messages/send_message.py +++ b/pyrogram/methods/messages/send_message.py @@ -36,6 +36,7 @@ class SendMessage: disable_notification: bool = None, message_thread_id: int = None, reply_to_message_id: int = None, + reply_to_story_id: int = None, schedule_date: datetime = None, protect_content: bool = None, reply_markup: Union[ @@ -78,6 +79,9 @@ class SendMessage: 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. schedule_date (:py:obj:`~datetime.datetime`, *optional*): Date when the message will be automatically sent. @@ -132,6 +136,9 @@ class SendMessage: reply_to = None if reply_to_message_id or message_thread_id: reply_to = types.InputReplyToMessage(reply_to_message_id=reply_to_message_id, message_thread_id=message_thread_id) + if reply_to_story_id: + user_id = await self.resolve_peer(chat_id) + reply_to = types.InputReplyToStory(user_id=user_id, story_id=reply_to_story_id) r = await self.invoke( raw.functions.messages.SendMessage( diff --git a/pyrogram/methods/messages/send_photo.py b/pyrogram/methods/messages/send_photo.py index 129a1b53..f04831e3 100644 --- a/pyrogram/methods/messages/send_photo.py +++ b/pyrogram/methods/messages/send_photo.py @@ -43,6 +43,7 @@ class SendPhoto: disable_notification: bool = None, message_thread_id: int = None, reply_to_message_id: int = None, + reply_to_story_id: int = None, schedule_date: datetime = None, protect_content: bool = None, reply_markup: Union[ @@ -99,6 +100,9 @@ class SendPhoto: 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. schedule_date (:py:obj:`~datetime.datetime`, *optional*): Date when the message will be automatically sent. @@ -156,6 +160,9 @@ class SendPhoto: reply_to = None if reply_to_message_id or message_thread_id: reply_to = types.InputReplyToMessage(reply_to_message_id=reply_to_message_id, message_thread_id=message_thread_id) + if reply_to_story_id: + user_id = await self.resolve_peer(chat_id) + reply_to = types.InputReplyToStory(user_id=user_id, story_id=reply_to_story_id) try: if isinstance(photo, str): diff --git a/pyrogram/methods/messages/send_sticker.py b/pyrogram/methods/messages/send_sticker.py index 04d67965..3b6e7f53 100644 --- a/pyrogram/methods/messages/send_sticker.py +++ b/pyrogram/methods/messages/send_sticker.py @@ -39,6 +39,7 @@ class SendSticker: disable_notification: bool = None, message_thread_id: int = None, reply_to_message_id: int = None, + reply_to_story_id: int = None, schedule_date: datetime = None, protect_content: bool = None, reply_markup: Union[ @@ -77,6 +78,9 @@ class SendSticker: 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. schedule_date (:py:obj:`~datetime.datetime`, *optional*): Date when the message will be automatically sent. @@ -129,6 +133,9 @@ class SendSticker: reply_to = None if reply_to_message_id or message_thread_id: reply_to = types.InputReplyToMessage(reply_to_message_id=reply_to_message_id, message_thread_id=message_thread_id) + if reply_to_story_id: + user_id = await self.resolve_peer(chat_id) + reply_to = types.InputReplyToStory(user_id=user_id, story_id=reply_to_story_id) try: if isinstance(sticker, str): diff --git a/pyrogram/methods/messages/send_video.py b/pyrogram/methods/messages/send_video.py index fea3281d..ef8585c7 100644 --- a/pyrogram/methods/messages/send_video.py +++ b/pyrogram/methods/messages/send_video.py @@ -50,6 +50,7 @@ class SendVideo: disable_notification: bool = None, message_thread_id: int = None, reply_to_message_id: int = None, + reply_to_story_id: int = None, schedule_date: datetime = None, protect_content: bool = None, reply_markup: Union[ @@ -129,6 +130,9 @@ class SendVideo: 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. schedule_date (:py:obj:`~datetime.datetime`, *optional*): Date when the message will be automatically sent. @@ -189,6 +193,9 @@ class SendVideo: reply_to = None if reply_to_message_id or message_thread_id: reply_to = types.InputReplyToMessage(reply_to_message_id=reply_to_message_id, message_thread_id=message_thread_id) + if reply_to_story_id: + user_id = await self.resolve_peer(chat_id) + reply_to = types.InputReplyToStory(user_id=user_id, story_id=reply_to_story_id) try: if isinstance(video, str): diff --git a/pyrogram/methods/messages/send_video_note.py b/pyrogram/methods/messages/send_video_note.py index 43ecb791..a1285a6d 100644 --- a/pyrogram/methods/messages/send_video_note.py +++ b/pyrogram/methods/messages/send_video_note.py @@ -41,6 +41,7 @@ class SendVideoNote: disable_notification: bool = None, message_thread_id: int = None, reply_to_message_id: int = None, + reply_to_story_id: int = None, schedule_date: datetime = None, protect_content: bool = None, reply_markup: Union[ @@ -90,7 +91,10 @@ class SendVideoNote: for forum supergroups only. reply_to_message_id (``int``, *optional*): - If the message is a reply, ID of the original message + If the message is a reply, ID of the original message. + + reply_to_story_id (``int``, *optional*): + Unique identifier for the target story. schedule_date (:py:obj:`~datetime.datetime`, *optional*): Date when the message will be automatically sent. @@ -143,6 +147,9 @@ class SendVideoNote: reply_to = None if reply_to_message_id or message_thread_id: reply_to = types.InputReplyToMessage(reply_to_message_id=reply_to_message_id, message_thread_id=message_thread_id) + if reply_to_story_id: + user_id = await self.resolve_peer(chat_id) + reply_to = types.InputReplyToStory(user_id=user_id, story_id=reply_to_story_id) try: if isinstance(video_note, str): diff --git a/pyrogram/methods/messages/send_voice.py b/pyrogram/methods/messages/send_voice.py index 2cfa5c5a..b07f4c59 100644 --- a/pyrogram/methods/messages/send_voice.py +++ b/pyrogram/methods/messages/send_voice.py @@ -43,6 +43,7 @@ class SendVoice: disable_notification: bool = None, message_thread_id: int = None, reply_to_message_id: int = None, + reply_to_story_id: int = None, schedule_date: datetime = None, protect_content: bool = None, reply_markup: Union[ @@ -94,6 +95,12 @@ class SendVoice: 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. + + reply_to_story_id (``int``, *optional*): + Unique identifier for the target story. schedule_date (:py:obj:`~datetime.datetime`, *optional*): Date when the message will be automatically sent. @@ -148,6 +155,9 @@ class SendVoice: reply_to = None if reply_to_message_id or message_thread_id: reply_to = types.InputReplyToMessage(reply_to_message_id=reply_to_message_id, message_thread_id=message_thread_id) + if reply_to_story_id: + user_id = await self.resolve_peer(chat_id) + reply_to = types.InputReplyToStory(user_id=user_id, story_id=reply_to_story_id) try: if isinstance(voice, str): diff --git a/pyrogram/methods/users/__init__.py b/pyrogram/methods/users/__init__.py index 31fda1dc..53fdd781 100644 --- a/pyrogram/methods/users/__init__.py +++ b/pyrogram/methods/users/__init__.py @@ -18,12 +18,17 @@ from .block_user import BlockUser from .delete_profile_photos import DeleteProfilePhotos +from .delete_stories import DeleteStories +from .edit_story import EditStory +from .export_story_link import ExportStoryLink from .get_chat_photos import GetChatPhotos from .get_chat_photos_count import GetChatPhotosCount from .get_common_chats import GetCommonChats from .get_default_emoji_statuses import GetDefaultEmojiStatuses from .get_me import GetMe +from .get_stories import GetStories from .get_users import GetUsers +from .send_story import SendStory from .set_emoji_status import SetEmojiStatus from .set_profile_photo import SetProfilePhoto from .set_username import SetUsername @@ -33,17 +38,22 @@ from .update_profile import UpdateProfile class Users( BlockUser, + DeleteStories, + EditStory, + ExportStoryLink, GetCommonChats, GetChatPhotos, SetProfilePhoto, DeleteProfilePhotos, GetUsers, GetMe, + GetStories, SetUsername, GetChatPhotosCount, UnblockUser, UpdateProfile, GetDefaultEmojiStatuses, - SetEmojiStatus + SetEmojiStatus, + SendStory ): pass diff --git a/pyrogram/methods/users/delete_stories.py b/pyrogram/methods/users/delete_stories.py new file mode 100644 index 00000000..aa1681d8 --- /dev/null +++ b/pyrogram/methods/users/delete_stories.py @@ -0,0 +1,65 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2022-present Mayuri-Chan +# +# This file is part of Pyrofork. +# +# Pyrofork 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. +# +# Pyrofork 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 Pyrofork. If not, see . + +import logging +from typing import Union, List, Iterable + +import pyrogram +from pyrogram import raw +from pyrogram import types + +log = logging.getLogger(__name__) + +class DeleteStories: + async def delete_stories( + self: "pyrogram.Client", + story_ids: Union[int, Iterable[int]], + ) -> bool: + """Delete one or more story by using story identifiers. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + story_ids (``int`` | Iterable of ``int``): + Pass a single story identifier or an iterable of story ids (as integers) to get the content of the + story themselves. + + Returns: + `bool`: On success, a True is returned. + + Example: + .. code-block:: python + + # Delete one story + await app.delete_stories(12345) + + # Delete more than one story (list of stories) + await app.delete_stories([12345, 12346]) + """ + + is_iterable = not isinstance(story_ids, int) + ids = list(story_ids) if is_iterable else [story_ids] + + try: + await self.invoke( + raw.functions.stories.DeleteStories(id=ids) + ) + except Exception as e: + print(e) + return False + return True diff --git a/pyrogram/methods/users/edit_story.py b/pyrogram/methods/users/edit_story.py new file mode 100644 index 00000000..4f22ffae --- /dev/null +++ b/pyrogram/methods/users/edit_story.py @@ -0,0 +1,240 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2022-present Mayuri-Chan +# +# This file is part of Pyrofork. +# +# Pyrofork 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. +# +# Pyrofork 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 Pyrofork. If not, see . + +import os +import re +from typing import List + +import pyrogram +from pyrogram import enums, raw, types, utils +from pyrogram.file_id import FileType + +class EditStory: + def _split(self, message, entities, *args, **kwargs): + return message, entities + + async def edit_story( + self: "pyrogram.Client", + story_id: int, + privacy: "enums.StoriesPrivacy" = None, + allowed_users: List[int] = None, + denied_users: List[int] = None, + allowed_chats: List[int] = None, + denied_chats: List[int] = None, + animation: str = None, + photo: str = None, + video: str = None, + caption: str = None, + parse_mode: "enums.ParseMode" = None, + caption_entities: List["types.MessageEntity"] = None + ) -> "types.Story": + """Edit story. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + story_id (``int``): + Unique identifier (int) of the target story. + + animation (``str`` | ``BinaryIO``, *optional*): + New story Animation. + Pass a file_id as string to send a animation that exists on the Telegram servers, + pass an HTTP URL as a string for Telegram to get a animation from the Internet, + pass a file path as string to upload a new animation that exists on your local machine, or + pass a binary file-like object with its attribute ".name" set for in-memory uploads. + + photo (``str`` | ``BinaryIO``, *optional*): + New story photo. + 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, + 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. + + video (``str`` | ``BinaryIO``, *optional*): + New story video. + 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, + 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. + + privacy (:obj:`~pyrogram.enums.StoriesPrivacy`, *optional*): + Story privacy. + + allowed_chats (List of ``int``, *optional*): + List of chat_id which participant allowed to view the story. + + denied_chats (List of ``int``, *optional*): + List of chat_id which participant denied to view the story. + + allowed_users (List of ``int``, *optional*): + List of user_id whos allowed to view the story. + + denied_users (List of ``int``, *optional*): + List of user_id whos denied to view the story. + + caption (``str``, *optional*): + Story caption, 0-1024 characters. + + 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*. + + Returns: + :obj:`~pyrogram.types.Story` a single story is returned. + + Example: + .. code-block:: python + + # Edit story photo + photo_id = "abcd12345" + await app.edit_story(story_id=1, photo=photo_id) + + Raises: + ValueError: In case of invalid arguments. + """ + + # TODO: MediaArea + + media = None + + if privacy: + privacy_rules = [types.StoriesPrivacy(type=privacy)] + + if animation: + if isinstance(animation, str): + if os.path.isfile(animation): + file = await self.save_file(animation) + media = raw.types.InputMediaUploadedDocument( + mime_type=self.guess_mime_type(animation) or "video/mp4", + file=file, + attributes=[ + raw.types.DocumentAttributeVideo( + supports_streaming=True, + duration=0, + w=0, + h=0 + ), + raw.types.DocumentAttributeAnimated() + ] + ) + elif re.match("^https?://", animation): + media = raw.types.InputMediaDocumentExternal( + url=animation + ) + else: + media = utils.get_input_media_from_file_id(animation, FileType.ANIMATION) + else: + file = await self.save_file(animation) + media = raw.types.InputMediaUploadedDocument( + mime_type=self.guess_mime_type(animation) or "video/mp4", + file=file, + attributes=[ + raw.types.DocumentAttributeVideo( + supports_streaming=True, + duration=0, + w=0, + h=0 + ), + raw.types.DocumentAttributeAnimated() + ] + ) + elif photo: + if isinstance(photo, str): + if os.path.isfile(photo): + file = await self.save_file(photo) + media = raw.types.InputMediaUploadedPhoto( + file=file + ) + elif re.match("^https?://", photo): + media = raw.types.InputMediaPhotoExternal( + url=photo + ) + else: + media = utils.get_input_media_from_file_id(photo, FileType.PHOTO) + else: + file = await self.save_file(photo) + media = raw.types.InputMediaUploadedPhoto( + file=file + ) + elif video: + if isinstance(video, str): + if os.path.isfile(video): + file = await self.save_file(video) + media = raw.types.InputMediaUploadedDocument( + mime_type=self.guess_mime_type(video) or "video/mp4", + file=file, + attributes=[ + raw.types.DocumentAttributeVideo( + supports_streaming=True, + duration=0, + w=0, + h=0 + ) + ] + ) + elif re.match("^https?://", video): + media = raw.types.InputMediaDocumentExternal( + url=video + ) + else: + media = utils.get_input_media_from_file_id(video, FileType.VIDEO) + else: + file = await self.save_file(video) + media = raw.types.InputMediaUploadedDocument( + mime_type=self.guess_mime_type(video) or "video/mp4", + file=file, + attributes=[ + raw.types.DocumentAttributeVideo( + supports_streaming=True, + duration=0, + w=0, + h=0 + ) + ] + ) + text = None + entities = None + if caption: + text, entities = self._split(**await utils.parse_text_entities(self, caption, parse_mode, caption_entities)) + + if allowed_chats and len(allowed_chats) > 0: + chats = [await self.resolve_peer(chat_id) for chat_id in allowed_chats] + privacy_rules.append(raw.types.InputPrivacyValueAllowChatParticipants(chats=chats)) + if denied_chats and len(denied_chats) > 0: + chats = [await self.resolve_peer(chat_id) for chat_id in denied_chats] + privacy_rules.append(raw.types.InputPrivacyValueDisallowChatParticipants(chats=chats)) + if allowed_users and len(allowed_users) > 0: + users = [await self.resolve_peer(user_id) for user_id in allowed_users] + privacy_rules.append(raw.types.InputPrivacyValueAllowUsers(users=users)) + if denied_users and len(denied_users) > 0: + users = [await self.resolve_peer(user_id) for user_id in denied_users] + privacy_rules.append(raw.types.InputPrivacyValueDisallowUsers(users=users)) + + r = await self.invoke( + raw.functions.stories.EditStory( + id=story_id, + media=media, + privacy_rules=privacy_rules, + caption=text, + entities=entities + ) + ) + return await types.Story._parse(self, r.updates[0].story, r.updates[0].user_id) diff --git a/pyrogram/methods/users/export_story_link.py b/pyrogram/methods/users/export_story_link.py new file mode 100644 index 00000000..c56036d5 --- /dev/null +++ b/pyrogram/methods/users/export_story_link.py @@ -0,0 +1,66 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2022-present Mayuri-Chan +# +# This file is part of Pyrofork. +# +# Pyrofork 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. +# +# Pyrofork 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 Pyrofork. If not, see . + +import logging +from typing import Union + +import pyrogram +from pyrogram import raw +from pyrogram import types + +log = logging.getLogger(__name__) + +class ExportStoryLink: + async def export_story_link( + self: "pyrogram.Client", + user_id: Union[int, str], + story_id: int, + ) -> types.ExportedStoryLink: + """Get one story link from an user by using story identifiers. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + user_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the target user. + For your personal story you can simply use "me" or "self". + For a contact that exists in your Telegram address book you can use his phone number (str). + + story_id (``int``): + Pass a single story identifier of story (as integers). + + Returns: + :obj:`~pyrogram.types.ExportedStoryLink`: a single story link is returned. + + Example: + .. code-block:: python + + # Get story link + await app.export_story_link(user_id, 12345) + + Raises: + ValueError: In case of invalid arguments. + """ + + peer = await self.resolve_peer(user_id) + + rpc = raw.functions.stories.ExportStoryLink(user_id=peer, story_id=story_id) + + r = await self.invoke(rpc, sleep_threshold=-1) + + return types.ExportedStoryLink._parse(r) diff --git a/pyrogram/methods/users/get_stories.py b/pyrogram/methods/users/get_stories.py new file mode 100644 index 00000000..b7e76f9a --- /dev/null +++ b/pyrogram/methods/users/get_stories.py @@ -0,0 +1,76 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2022-present Mayuri-Chan +# +# This file is part of Pyrofork. +# +# Pyrofork 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. +# +# Pyrofork 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 Pyrofork. If not, see . + +import logging +from typing import Union, List, Iterable + +import pyrogram +from pyrogram import raw +from pyrogram import types + +log = logging.getLogger(__name__) + +class GetStories: + async def get_stories( + self: "pyrogram.Client", + user_id: Union[int, str], + story_ids: Union[int, Iterable[int]], + ) -> Union["types.Story", List["types.Story"]]: + """Get one or more story from an user by using story identifiers. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + user_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the target user. + For your personal story you can simply use "me" or "self". + For a contact that exists in your Telegram address book you can use his phone number (str). + + story_ids (``int`` | Iterable of ``int``, *optional*): + Pass a single story identifier or an iterable of story ids (as integers) to get the content of the + story themselves. + + Returns: + :obj:`~pyrogram.types.Story` | List of :obj:`~pyrogram.types.Story`: In case *story_ids* was not + a list, a single story is returned, otherwise a list of stories is returned. + + Example: + .. code-block:: python + + # Get one story + await app.get_stories(user_id, 12345) + + # Get more than one story (list of stories) + await app.get_stories(user_id, [12345, 12346]) + + Raises: + ValueError: In case of invalid arguments. + """ + + peer = await self.resolve_peer(user_id) + + is_iterable = not isinstance(story_ids, int) + ids = list(story_ids) if is_iterable else [story_ids] + + rpc = raw.functions.stories.GetStoriesByID(user_id=peer, id=ids) + + r = await self.invoke(rpc, sleep_threshold=-1) + + if is_iterable: + return types.List([await types.Story._parse(self, story, user_id) for story in r.stories]) + return await types.Story._parse(self, r.stories[0], user_id) diff --git a/pyrogram/methods/users/send_story.py b/pyrogram/methods/users/send_story.py new file mode 100644 index 00000000..c68d2f76 --- /dev/null +++ b/pyrogram/methods/users/send_story.py @@ -0,0 +1,256 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2022-present Mayuri-Chan +# +# This file is part of Pyrofork. +# +# Pyrofork 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. +# +# Pyrofork 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 Pyrofork. If not, see . + +import os +import re +from typing import List + +import pyrogram +from pyrogram import enums, raw, types, utils +from pyrogram.file_id import FileType + +class SendStory: + def _split(self, message, entities, *args, **kwargs): + return message, entities + + async def send_story( + self: "pyrogram.Client", + privacy: "enums.StoriesPrivacy" = None, + allowed_users: List[int] = None, + denied_users: List[int] = None, + allowed_chats: List[int] = None, + denied_chats: List[int] = None, + animation: str = None, + photo: str = None, + video: str = None, + pinned: bool = None, + protect_content: bool = None, + caption: str = None, + parse_mode: "enums.ParseMode" = None, + caption_entities: List["types.MessageEntity"] = None, + period: int = None + ) -> "types.Story": + """Send new story. + + .. include:: /_includes/usable-by/users.rst + + Note: You must pass one of following paramater *animation*, *photo*, *video* + + Parameters: + animation (``str`` | ``BinaryIO``, *optional*): + Animation to send. + Pass a file_id as string to send a animation that exists on the Telegram servers, + pass an HTTP URL as a string for Telegram to get a animation from the Internet, + pass a file path as string to upload a new animation that exists on your local machine, or + pass a binary file-like object with its attribute ".name" set for in-memory uploads. + + photo (``str`` | ``BinaryIO``, *optional*): + 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, + 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. + + video (``str`` | ``BinaryIO``, *optional*): + 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, + 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. + + privacy (:obj:`~pyrogram.enums.StoriesPrivacy`, *optional*): + Story privacy. + Defaults to :obj:`~pyrogram.enums.StoriesPrivacy.PUBLIC` + + allowed_chats (List of ``int``, *optional*): + List of chat_id which participant allowed to view the story. + + denied_chats (List of ``int``, *optional*): + List of chat_id which participant denied to view the story. + + allowed_users (List of ``int``, *optional*): + List of user_id whos allowed to view the story. + + denied_users (List of ``int``, *optional*): + List of user_id whos denied to view the story. + + pinned (``bool``, *optional*): + if True, the story will be pinned. + default to False. + + protect_content (``bool``, *optional*): + Protects the contents of the sent story from forwarding and saving. + default to False. + + caption (``str``, *optional*): + Story caption, 0-1024 characters. + + 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*. + + period (``int``, *optional*): + How long the story will posted, in secs. + only for premium users. + + Returns: + :obj:`~pyrogram.types.Story` a single story is returned. + + Example: + .. code-block:: python + + # Send new photo story + photo_id = "abcd12345" + await app.send_story(photo=photo_id, caption='Hello guys.') + + Raises: + ValueError: In case of invalid arguments. + """ + # TODO: media_areas + + if privacy: + privacy_rules = [types.StoriesPrivacy(type=privacy)] + else: + privacy_rules = [types.StoriesPrivacy(type=enums.StoriesPrivacy.PUBLIC)] + + if animation: + if isinstance(animation, str): + if os.path.isfile(animation): + file = await self.save_file(animation) + media = raw.types.InputMediaUploadedDocument( + mime_type=self.guess_mime_type(animation) or "video/mp4", + file=file, + attributes=[ + raw.types.DocumentAttributeVideo( + supports_streaming=True, + duration=0, + w=0, + h=0 + ), + raw.types.DocumentAttributeAnimated() + ] + ) + elif re.match("^https?://", animation): + media = raw.types.InputMediaDocumentExternal( + url=animation + ) + else: + media = utils.get_input_media_from_file_id(animation, FileType.ANIMATION) + else: + file = await self.save_file(animation) + media = raw.types.InputMediaUploadedDocument( + mime_type=self.guess_mime_type(animation) or "video/mp4", + file=file, + attributes=[ + raw.types.DocumentAttributeVideo( + supports_streaming=True, + duration=0, + w=0, + h=0 + ), + raw.types.DocumentAttributeAnimated() + ] + ) + elif photo: + if isinstance(photo, str): + if os.path.isfile(photo): + file = await self.save_file(photo) + media = raw.types.InputMediaUploadedPhoto( + file=file + ) + elif re.match("^https?://", photo): + media = raw.types.InputMediaPhotoExternal( + url=photo + ) + else: + media = utils.get_input_media_from_file_id(photo, FileType.PHOTO) + else: + file = await self.save_file(photo) + media = raw.types.InputMediaUploadedPhoto( + file=file + ) + elif video: + if isinstance(video, str): + if os.path.isfile(video): + file = await self.save_file(video) + media = raw.types.InputMediaUploadedDocument( + mime_type=self.guess_mime_type(video) or "video/mp4", + file=file, + attributes=[ + raw.types.DocumentAttributeVideo( + supports_streaming=True, + duration=0, + w=0, + h=0 + ) + ] + ) + elif re.match("^https?://", video): + media = raw.types.InputMediaDocumentExternal( + url=video + ) + else: + media = utils.get_input_media_from_file_id(video, FileType.VIDEO) + else: + file = await self.save_file(video) + media = raw.types.InputMediaUploadedDocument( + mime_type=self.guess_mime_type(video) or "video/mp4", + file=file, + attributes=[ + raw.types.DocumentAttributeVideo( + supports_streaming=True, + duration=0, + w=0, + h=0 + ) + ] + ) + else: + raise ValueError("You need to pass one of the following parameter animation/photo/video!") + + text, entities = self._split(**await utils.parse_text_entities(self, caption, parse_mode, caption_entities)) + + if allowed_chats and len(allowed_chats) > 0: + chats = [await self.resolve_peer(chat_id) for chat_id in allowed_chats] + privacy_rules.append(raw.types.InputPrivacyValueAllowChatParticipants(chats=chats)) + if denied_chats and len(denied_chats) > 0: + chats = [await self.resolve_peer(chat_id) for chat_id in denied_chats] + privacy_rules.append(raw.types.InputPrivacyValueDisallowChatParticipants(chats=chats)) + if allowed_users and len(allowed_users) > 0: + users = [await self.resolve_peer(user_id) for user_id in allowed_users] + privacy_rules.append(raw.types.InputPrivacyValueAllowUsers(users=users)) + if denied_users and len(denied_users) > 0: + users = [await self.resolve_peer(user_id) for user_id in denied_users] + privacy_rules.append(raw.types.InputPrivacyValueDisallowUsers(users=users)) + + r = await self.invoke( + raw.functions.stories.SendStory( + media=media, + privacy_rules=privacy_rules, + random_id=self.rnd_id(), + pinned=pinned, + noforwards=protect_content, + caption=text, + entities=entities, + period=period + ) + ) + return await types.Story._parse(self, r.updates[0].story, r.updates[0].user_id) diff --git a/pyrogram/types/input_message_content/__init__.py b/pyrogram/types/input_message_content/__init__.py index 8312cfd4..ffc05f33 100644 --- a/pyrogram/types/input_message_content/__init__.py +++ b/pyrogram/types/input_message_content/__init__.py @@ -19,8 +19,9 @@ from .input_message_content import InputMessageContent from .input_reply_to_message import InputReplyToMessage +from .input_reply_to_story import InputReplyToStory from .input_text_message_content import InputTextMessageContent __all__ = [ - "InputMessageContent", "InputReplyToMessage", "InputTextMessageContent" + "InputMessageContent", "InputReplyToMessage", "InputReplyToStory", "InputTextMessageContent" ] diff --git a/pyrogram/types/input_message_content/input_reply_to_story.py b/pyrogram/types/input_message_content/input_reply_to_story.py new file mode 100644 index 00000000..c521e4b0 --- /dev/null +++ b/pyrogram/types/input_message_content/input_reply_to_story.py @@ -0,0 +1,49 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2022-present Mayuri-Chan +# +# This file is part of Pyrofork. +# +# Pyrofork 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. +# +# Pyrofork 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 Pyrofork. If not, see . + +from pyrogram import raw +from ..object import Object + + +class InputReplyToStory(Object): + """Contains information about a target replied story. + + + Parameters: + user_id (:obj:`~pyrogram.raw.types.InputUser`): + An InputUser. + + story_id (``int``): + Unique identifier for the target story. + """ + + def __init__( + self, *, + user_id: "raw.types.InputUser" = None, + story_id: int = None + ): + super().__init__() + + self.user_id = user_id + self.story_id = story_id + + def write(self): + return raw.types.InputReplyToStory( + user_id=self.user_id, + story_id=self.story_id + ).write() diff --git a/pyrogram/types/messages_and_media/__init__.py b/pyrogram/types/messages_and_media/__init__.py index f6e93801..f1d64ae6 100644 --- a/pyrogram/types/messages_and_media/__init__.py +++ b/pyrogram/types/messages_and_media/__init__.py @@ -31,6 +31,7 @@ from .poll_option import PollOption from .reaction import Reaction from .sticker import Sticker from .stickerset import StickerSet +from .stories_privacy import StoriesPrivacy from .stripped_thumbnail import StrippedThumbnail from .thumbnail import Thumbnail from .venue import Venue @@ -40,9 +41,12 @@ from .voice import Voice from .web_app_data import WebAppData from .web_page import WebPage from .message_reactions import MessageReactions +from .story import Story +from .story_views import StoryViews +from .exported_story_link import ExportedStoryLink __all__ = [ "Animation", "Audio", "Contact", "Document", "Game", "Location", "Message", "MessageEntity", "Photo", "Thumbnail", "StrippedThumbnail", "Poll", "PollOption", "Sticker", "StickerSet", "Venue", "Video", "VideoNote", "Voice", "WebPage", "Dice", - "Reaction", "WebAppData", "MessageReactions" + "Reaction", "WebAppData", "MessageReactions", "Story", "StoryViews", "StoriesPrivacy", "ExportedStoryLink" ] diff --git a/pyrogram/types/messages_and_media/exported_story_link.py b/pyrogram/types/messages_and_media/exported_story_link.py new file mode 100644 index 00000000..15287904 --- /dev/null +++ b/pyrogram/types/messages_and_media/exported_story_link.py @@ -0,0 +1,44 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2022-present Mayuri-Chan +# +# This file is part of Pyrofork. +# +# Pyrofork 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. +# +# Pyrofork 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 Pyrofork. If not, see . + +from pyrogram import raw +from typing import List +from ..object import Object + +class ExportedStoryLink(Object): + """Contains information about a story viewers. + + + Parameters: + link (``str``): + The link of the story. + """ + + def __init__( + self, *, + link: str + ): + super().__init__() + + self.link = link + + @staticmethod + def _parse(exportedstorylink: "raw.types.ExportedStoryLink") -> "ExportedStoryLink": + return ExportedStoryLink( + link=getattr(exportedstorylink,"link", None) + ) diff --git a/pyrogram/types/messages_and_media/stories_privacy.py b/pyrogram/types/messages_and_media/stories_privacy.py new file mode 100644 index 00000000..512930b1 --- /dev/null +++ b/pyrogram/types/messages_and_media/stories_privacy.py @@ -0,0 +1,47 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2022-present Mayuri-Chan +# +# This file is part of Pyrofork. +# +# Pyrofork 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. +# +# Pyrofork 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 Pyrofork. If not, see . + +from pyrogram import enums, raw +from ..object import Object + +class StoriesPrivacy(Object): + """A story privacy. + + Parameters: + type (:obj:`~pyrogram.enums.StoriesPrivacy`): + Story privacy type. + """ + + def __init__( + self, *, + type: "enums.StoriesPrivacy" + ): + super().__init__() + self.type = type + + def write(self): + if self.type == enums.StoriesPrivacy.PUBLIC: + return raw.types.InputPrivacyValueAllowAll().write() + if self.type == enums.StoriesPrivacy.CLOSE_FRIENDS: + return raw.types.InputPrivacyValueAllowCloseFriends().write() + if self.type == enums.StoriesPrivacy.CONTACTS: + return raw.types.InputPrivacyValueAllowContacts().write() + if self.type == enums.StoriesPrivacy.NO_CONTACTS: + return raw.types.InputPrivacyValueDisallowContacts().write() + if self.type == enums.StoriesPrivacy.PRIVATE: + return raw.types.InputPrivacyValueDisallowAll().write() diff --git a/pyrogram/types/messages_and_media/story.py b/pyrogram/types/messages_and_media/story.py new file mode 100644 index 00000000..b238d292 --- /dev/null +++ b/pyrogram/types/messages_and_media/story.py @@ -0,0 +1,1638 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2022-present Mayuri-Chan +# +# This file is part of Pyrofork. +# +# Pyrofork 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. +# +# Pyrofork 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 Pyrofork. If not, see . + +import pyrogram + +from datetime import datetime +from pyrogram import enums, raw, types, utils +from typing import BinaryIO, Callable, List, Optional, Union +from ..object import Object +from ..update import Update + +class Story(Object, Update): + """A story. + + Parameters: + id (``int``): + Unique story identifier. + + from_user (:obj:`~pyrogram.types.User`, *optional*): + Sender of the story. + + date (:py:obj:`~datetime.datetime`, *optional*): + Date the story was sent. + + expire_date (:py:obj:`~datetime.datetime`, *optional*): + Date the story will be expired. + + media (:obj:`~pyrogram.enums.MessageMediaType`, *optional*): + The media type of the Story. + This field will contain the enumeration type of the media message. + You can use ``media = getattr(message, message.media.value)`` to access the media message. + + has_protected_content (``bool``, *optional*): + True, if the story can't be forwarded. + + animation (:obj:`~pyrogram.types.Animation`, *optional*): + Story is an animation, information about the animation. + + photo (:obj:`~pyrogram.types.Photo`, *optional*): + Story is a photo, information about the photo. + + video (:obj:`~pyrogram.types.Video`, *optional*): + Story is a video, information about the video. + + edited (``bool``, *optional*): + True, if the Story has been edited. + + pinned (``bool``, *optional*): + True, if the Story is pinned. + + public (``bool``, *optional*): + True, if the Story is shared with public. + + close_friends (``bool``, *optional*): + True, if the Story is shared with close_friends only. + + contacts (``bool``, *optional*): + True, if the Story is shared with contacts only. + + selected_contacts (``bool``, *optional*): + True, if the Story is shared with selected contacts only. + + caption (``str``, *optional*): + Caption for the Story, 0-1024 characters. + + caption_entities (List of :obj:`~pyrogram.types.MessageEntity`, *optional*): + For text messages, special entities like usernames, URLs, bot commands, etc. that appear in the caption. + + views (:obj:`~pyrogram.types.StoryViews`, *optional*): + Stories views. + """ + + # TODO: Add Privacy + + def __init__( + self, + *, + client: "pyrogram.Client" = None, + id: int, + from_user: "types.User", + date: datetime, + expire_date: datetime, + media: "enums.MessageMediaType", + has_protected_content: bool = None, + animation: "types.Animation" = None, + photo: "types.Photo" = None, + video: "types.Video" = None, + edited: bool = None, + pinned: bool = None, + public: bool = None, + close_friends: bool = None, + contacts: bool = None, + selected_contacts: bool = None, + caption: str = None, + caption_entities: List["types.MessageEntity"] = None, + views: "types.StoryViews" = None + ): + super().__init__(client) + + self.id = id + self.from_user = from_user + self.date = date + self.expire_date = expire_date + self.media = media + self.has_protected_content = has_protected_content + self.animation = animation + self.photo = photo + self.video = video + self.edited = edited + self.pinned = pinned + self.public = public + self.close_friends = close_friends + self.contacts = contacts + self.selected_contacts = selected_contacts + self.caption = caption + self.caption_entities = caption_entities + self.views = views + + @staticmethod + async def _parse( + client: "pyrogram.Client", + stories: raw.base.StoryItem, + user_id: int + ) -> "Story": + entities = [types.MessageEntity._parse(client, entity, {}) for entity in stories.entities] + entities = types.List(filter(lambda x: x is not None, entities)) + animation = None + photo = None + video = None + if stories.media: + if isinstance(stories.media, raw.types.MessageMediaPhoto): + photo = types.Photo._parse(client, stories.media.photo, stories.media.ttl_seconds) + media_type = enums.MessageMediaType.PHOTO + elif isinstance(stories.media, raw.types.MessageMediaDocument): + doc = stories.media.document + + if isinstance(doc, raw.types.Document): + attributes = {type(i): i for i in doc.attributes} + + if raw.types.DocumentAttributeAnimated in attributes: + video_attributes = attributes.get(raw.types.DocumentAttributeVideo, None) + animation = types.Animation._parse(client, doc, video_attributes, None) + media_type = enums.MessageMediaType.ANIMATION + elif raw.types.DocumentAttributeVideo in attributes: + video_attributes = attributes.get(raw.types.DocumentAttributeVideo, None) + video = types.Video._parse(client, doc, video_attributes, None, stories.media.ttl_seconds) + media_type = enums.MessageMediaType.VIDEO + else: + media_type = None + else: + media_type = None + from_user = await client.get_users(user_id) + + return Story( + id=stories.id, + from_user=from_user, + date=utils.timestamp_to_datetime(stories.date), + expire_date=utils.timestamp_to_datetime(stories.expire_date), + media=media_type, + has_protected_content=stories.noforwards, + animation=animation, + photo=photo, + video=video, + edited=stories.edited, + pinned=stories.pinned, + public=stories.public, + close_friends=stories.close_friends, + contacts=stories.contacts, + selected_contacts=stories.selected_contacts, + caption=stories.caption, + caption_entities=entities or None, + views=types.StoryViews._parse(stories.views) + ) + + async def reply_text( + self, + text: str, + parse_mode: Optional["enums.ParseMode"] = None, + entities: List["types.MessageEntity"] = None, + disable_web_page_preview: bool = None, + disable_notification: bool = None, + reply_to_story_id: int = None, + schedule_date: datetime = None, + protect_content: bool = None, + reply_markup=None + ) -> "types.Message": + """Bound method *reply_text* of :obj:`~pyrogram.types.Story`. + + An alias exists as *reply*. + + Use as a shortcut for: + + .. code-block:: python + + await client.send_message( + chat_id=message.chat.id, + text="hello", + reply_to_story_id=story.id + ) + + Example: + .. code-block:: python + + await story.reply_text("hello", quote=True) + + Parameters: + text (``str``): + Text of the message to be sent. + + parse_mode (:obj:`~pyrogram.enums.ParseMode`, *optional*): + By default, texts are parsed using both Markdown and HTML styles. + You can combine both syntaxes together. + + entities (List of :obj:`~pyrogram.types.MessageEntity`): + List of special entities that appear in message text, which can be specified instead of *parse_mode*. + + disable_web_page_preview (``bool``, *optional*): + Disables link previews for links in this message. + + disable_notification (``bool``, *optional*): + Sends the message silently. + Users will receive a notification with no sound. + + reply_to_story_id (``int``, *optional*): + If the message is a reply, ID of the original story. + + schedule_date (:py:obj:`~datetime.datetime`, *optional*): + Date when the message will be automatically sent. + + protect_content (``bool``, *optional*): + Protects the contents of the sent message from forwarding and saving. + + 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. + + Returns: + On success, the sent Message is returned. + + Raises: + RPCError: In case of a Telegram RPC error. + """ + + if reply_to_story_id is None: + reply_to_story_id = self.id + + return await self._client.send_message( + chat_id=self.from_user.id, + text=text, + parse_mode=parse_mode, + entities=entities, + disable_web_page_preview=disable_web_page_preview, + disable_notification=disable_notification, + reply_to_story_id=reply_to_story_id, + schedule_date=schedule_date, + protect_content=protect_content, + reply_markup=reply_markup + ) + + reply = reply_text + + async def reply_animation( + self, + animation: Union[str, BinaryIO], + caption: str = "", + parse_mode: Optional["enums.ParseMode"] = None, + caption_entities: List["types.MessageEntity"] = None, + has_spoiler: bool = None, + duration: int = 0, + width: int = 0, + height: int = 0, + thumb: Union[str, BinaryIO] = None, + file_name: str = None, + disable_notification: bool = None, + reply_markup: Union[ + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" + ] = None, + reply_to_story_id: int = None, + progress: Callable = None, + progress_args: tuple = () + ) -> "types.Message": + """Bound method *reply_animation* :obj:`~pyrogram.types.Story`. + + Use as a shortcut for: + + .. code-block:: python + + await client.send_animation( + chat_id=story.from_user.id, + animation=animation, + reply_to_story_id=story.id + ) + + Example: + .. code-block:: python + + await story.reply_animation(animation) + + Parameters: + 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. + + caption (``str``, *optional*): + Animation caption, 0-1024 characters. + + 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*. + + has_spoiler (``bool``, *optional*): + Pass True if the animation needs to be covered with a spoiler animation. + + duration (``int``, *optional*): + Duration of sent animation in seconds. + + width (``int``, *optional*): + Animation width. + + height (``int``, *optional*): + Animation height. + + thumb (``str`` | ``BinaryIO``, *optional*): + Thumbnail of the animation file sent. + The thumbnail should be in JPEG format and less than 200 KB in size. + A thumbnail's width and height should not exceed 320 pixels. + Thumbnails can't be reused and can be only uploaded as a new file. + + file_name (``str``, *optional*): + File name of the animation sent. + Defaults to file's path basename. + + disable_notification (``bool``, *optional*): + Sends the message silently. + Users will receive a notification with no sound. + + reply_to_story_id (``int``, *optional*): + If the message is a reply, ID of the original message. + + 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. + + 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, the sent :obj:`~pyrogram.types.Message` is returned. + In case the upload is deliberately stopped with :meth:`~pyrogram.Client.stop_transmission`, None is returned + instead. + + Raises: + RPCError: In case of a Telegram RPC error. + """ + + if reply_to_story_id is None: + reply_to_story_id = self.id + + return await self._client.send_animation( + chat_id=self.from_user.id, + animation=animation, + caption=caption, + parse_mode=parse_mode, + caption_entities=caption_entities, + has_spoiler=has_spoiler, + duration=duration, + width=width, + height=height, + thumb=thumb, + file_name=file_name, + disable_notification=disable_notification, + reply_to_story_id=reply_to_story_id, + reply_markup=reply_markup, + progress=progress, + progress_args=progress_args + ) + + async def reply_audio( + self, + audio: Union[str, BinaryIO], + caption: str = "", + parse_mode: Optional["enums.ParseMode"] = None, + caption_entities: List["types.MessageEntity"] = None, + duration: int = 0, + performer: str = None, + title: str = None, + thumb: Union[str, BinaryIO] = None, + file_name: str = None, + disable_notification: bool = None, + reply_to_story_id: int = None, + reply_markup: Union[ + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" + ] = None, + progress: Callable = None, + progress_args: tuple = () + ) -> "types.Message": + """Bound method *reply_audio* of :obj:`~pyrogram.types.Story`. + + Use as a shortcut for: + + .. code-block:: python + + await client.send_audio( + chat_id=story.from_user.id, + audio=audio, + reply_to_story_id=story.id + ) + + Example: + .. code-block:: python + + await story.reply_audio(audio) + + Parameters: + 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. + + caption (``str``, *optional*): + Audio caption, 0-1024 characters. + + 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*. + + duration (``int``, *optional*): + Duration of the audio in seconds. + + performer (``str``, *optional*): + Performer. + + title (``str``, *optional*): + Track name. + + thumb (``str`` | ``BinaryIO``, *optional*): + Thumbnail of the music file album cover. + The thumbnail should be in JPEG format and less than 200 KB in size. + A thumbnail's width and height should not exceed 320 pixels. + Thumbnails can't be reused and can be only uploaded as a new file. + + file_name (``str``, *optional*): + File name of the audio sent. + Defaults to file's path basename. + + disable_notification (``bool``, *optional*): + Sends the message silently. + Users will receive a notification with no sound. + + reply_to_story_id (``int``, *optional*): + If the message is a reply, ID of the original message. + + 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. + + 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, the sent :obj:`~pyrogram.types.Message` is returned. + In case the upload is deliberately stopped with :meth:`~pyrogram.Client.stop_transmission`, None is returned + instead. + + Raises: + RPCError: In case of a Telegram RPC error. + """ + + if reply_to_story_id is None: + reply_to_story_id = self.id + + return await self._client.send_audio( + chat_id=self.from_user.id, + audio=audio, + caption=caption, + parse_mode=parse_mode, + caption_entities=caption_entities, + duration=duration, + performer=performer, + title=title, + thumb=thumb, + file_name=file_name, + disable_notification=disable_notification, + reply_to_story_id=reply_to_story_id, + reply_markup=reply_markup, + progress=progress, + progress_args=progress_args + ) + + async def reply_cached_media( + self, + file_id: str, + caption: str = "", + parse_mode: Optional["enums.ParseMode"] = None, + caption_entities: List["types.MessageEntity"] = None, + disable_notification: bool = None, + reply_to_story_id: int = None, + reply_markup: Union[ + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" + ] = None + ) -> "types.Message": + """Bound method *reply_cached_media* of :obj:`~pyrogram.types.Story`. + + Use as a shortcut for: + + .. code-block:: python + + await client.send_cached_media( + chat_id=story.from_user.id, + file_id=file_id, + reply_to_story_id=story.id + ) + + Example: + .. code-block:: python + + await story.reply_cached_media(file_id) + + Parameters: + file_id (``str``): + Media to send. + Pass a file_id as string to send a media that exists on the Telegram servers. + + caption (``bool``, *optional*): + Media caption, 0-1024 characters. + + 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*. + + disable_notification (``bool``, *optional*): + Sends the message silently. + Users will receive a notification with no sound. + + reply_to_story_id (``int``, *optional*): + If the message is a reply, ID of the original message. + + 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. + + Returns: + On success, the sent :obj:`~pyrogram.types.Message` is returned. + + Raises: + RPCError: In case of a Telegram RPC error. + """ + if reply_to_story_id is None: + reply_to_story_id = self.id + + return await self._client.send_cached_media( + chat_id=self.from_user.id, + file_id=file_id, + caption=caption, + parse_mode=parse_mode, + caption_entities=caption_entities, + disable_notification=disable_notification, + reply_to_story_id=reply_to_story_id, + reply_markup=reply_markup + ) + + async def reply_media_group( + self, + media: List[Union[ + "types.InputMediaPhoto", + "types.InputMediaVideo", + "types.InputMediaAudio", + "types.InputMediaDocument" + ]], + disable_notification: bool = None, + reply_to_story_id: int = None + ) -> List["types.Message"]: + """Bound method *reply_media_group* of :obj:`~pyrogram.types.Story`. + + Use as a shortcut for: + + .. code-block:: python + + await client.send_media_group( + chat_id=story.from_user.id, + media=list_of_media, + reply_to_story_id=story.id + ) + + Example: + .. code-block:: python + + await story.reply_media_group(list_of_media) + + Parameters: + media (``list``): + A list containing either :obj:`~pyrogram.types.InputMediaPhoto` or + :obj:`~pyrogram.types.InputMediaVideo` objects + describing photos and videos to be sent, must include 2–10 items. + + disable_notification (``bool``, *optional*): + Sends the message silently. + Users will receive a notification with no sound. + + reply_to_story_id (``int``, *optional*): + If the message is a reply, ID of the original message. + + Returns: + On success, a :obj:`~pyrogram.types.Messages` object is returned containing all the + single messages sent. + + Raises: + RPCError: In case of a Telegram RPC error. + """ + if reply_to_story_id is None: + reply_to_story_id = self.id + + return await self._client.send_media_group( + chat_id=self.chat.id, + media=media, + disable_notification=disable_notification, + reply_to_story_id=reply_to_story_id + ) + + async def reply_photo( + self, + photo: Union[str, BinaryIO], + caption: str = "", + parse_mode: Optional["enums.ParseMode"] = None, + caption_entities: List["types.MessageEntity"] = None, + has_spoiler: bool = None, + ttl_seconds: int = None, + disable_notification: bool = None, + reply_to_story_id: int = None, + reply_markup: Union[ + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" + ] = None, + progress: Callable = None, + progress_args: tuple = () + ) -> "types.Message": + """Bound method *reply_photo* of :obj:`~pyrogram.types.Story`. + + Use as a shortcut for: + + .. code-block:: python + + await client.send_photo( + chat_id=story.from_user.id, + photo=photo, + reply_to_story_id=story.id + ) + + Example: + .. code-block:: python + + await story.reply_photo(photo) + + Parameters: + 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. + + caption (``str``, *optional*): + Photo caption, 0-1024 characters. + + 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*. + + has_spoiler (``bool``, *optional*): + Pass True if the photo needs to be covered with a spoiler animation. + + ttl_seconds (``int``, *optional*): + Self-Destruct Timer. + If you set a timer, the photo will self-destruct in *ttl_seconds* + seconds after it was viewed. + + disable_notification (``bool``, *optional*): + Sends the message silently. + Users will receive a notification with no sound. + + reply_to_story_id (``int``, *optional*): + If the message is a reply, ID of the original message. + + 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. + + 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, the sent :obj:`~pyrogram.types.Message` is returned. + In case the upload is deliberately stopped with :meth:`~pyrogram.Client.stop_transmission`, None is returned + instead. + + Raises: + RPCError: In case of a Telegram RPC error. + """ + if reply_to_story_id is None: + reply_to_story_id = self.id + + return await self._client.send_photo( + chat_id=self.chat.id, + photo=photo, + caption=caption, + parse_mode=parse_mode, + caption_entities=caption_entities, + has_spoiler=has_spoiler, + ttl_seconds=ttl_seconds, + disable_notification=disable_notification, + reply_to_story_id=reply_to_story_id, + reply_markup=reply_markup, + progress=progress, + progress_args=progress_args + ) + + async def reply_sticker( + self, + sticker: Union[str, BinaryIO], + disable_notification: bool = None, + reply_to_story_id: int = None, + reply_markup: Union[ + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" + ] = None, + progress: Callable = None, + progress_args: tuple = () + ) -> "types.Message": + """Bound method *reply_sticker* of :obj:`~pyrogram.types.Story`. + + Use as a shortcut for: + + .. code-block:: python + + await client.send_sticker( + chat_id=story.from_user.id, + sticker=sticker, + reply_to_story_id=story.id + ) + + Example: + .. code-block:: python + + await story.reply_sticker(sticker) + + Parameters: + 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. + + disable_notification (``bool``, *optional*): + Sends the message silently. + Users will receive a notification with no sound. + + reply_to_story_id (``int``, *optional*): + If the message is a reply, ID of the original message. + + 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. + + 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, the sent :obj:`~pyrogram.types.Message` is returned. + In case the upload is deliberately stopped with :meth:`~pyrogram.Client.stop_transmission`, None is returned + instead. + + Raises: + RPCError: In case of a Telegram RPC error. + """ + + if reply_to_story_id is None: + reply_to_story_id = self.id + + return await self._client.send_sticker( + chat_id=self.chat.id, + sticker=sticker, + disable_notification=disable_notification, + reply_to_story_id=reply_to_story_id, + reply_markup=reply_markup, + progress=progress, + progress_args=progress_args + ) + + async def reply_video( + self, + video: Union[str, BinaryIO], + caption: str = "", + parse_mode: Optional["enums.ParseMode"] = None, + caption_entities: List["types.MessageEntity"] = None, + has_spoiler: bool = None, + ttl_seconds: int = None, + duration: int = 0, + width: int = 0, + height: int = 0, + thumb: Union[str, BinaryIO] = None, + file_name: str = None, + supports_streaming: bool = True, + disable_notification: bool = None, + reply_to_story_id: int = None, + reply_markup: Union[ + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" + ] = None, + progress: Callable = None, + progress_args: tuple = () + ) -> "types.Message": + """Bound method *reply_video* of :obj:`~pyrogram.types.Story`. + + Use as a shortcut for: + + .. code-block:: python + + await client.send_video( + chat_id=story.from_user.id, + video=video, + reply_to_story_id=story.id + ) + + Example: + .. code-block:: python + + await story.reply_video(video) + + Parameters: + 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. + + caption (``str``, *optional*): + Video caption, 0-1024 characters. + + 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*. + + has_spoiler (``bool``, *optional*): + Pass True if the video needs to be covered with a spoiler animation. + + ttl_seconds (``int``, *optional*): + Self-Destruct Timer. + If you set a timer, the video will self-destruct in *ttl_seconds* + seconds after it was viewed. + + duration (``int``, *optional*): + Duration of sent video in seconds. + + width (``int``, *optional*): + Video width. + + height (``int``, *optional*): + Video height. + + thumb (``str`` | ``BinaryIO``, *optional*): + Thumbnail of the video sent. + The thumbnail should be in JPEG format and less than 200 KB in size. + A thumbnail's width and height should not exceed 320 pixels. + Thumbnails can't be reused and can be only uploaded as a new file. + + file_name (``str``, *optional*): + File name of the video sent. + Defaults to file's path basename. + + supports_streaming (``bool``, *optional*): + Pass True, if the uploaded video is suitable for streaming. + + disable_notification (``bool``, *optional*): + Sends the message silently. + Users will receive a notification with no sound. + + reply_to_story_id (``int``, *optional*): + If the message is a reply, ID of the original message. + + 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. + + 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, the sent :obj:`~pyrogram.types.Message` is returned. + In case the upload is deliberately stopped with :meth:`~pyrogram.Client.stop_transmission`, None is returned + instead. + + Raises: + RPCError: In case of a Telegram RPC error. + """ + if reply_to_story_id is None: + reply_to_story_id = self.id + + return await self._client.send_video( + chat_id=self.chat.id, + video=video, + caption=caption, + parse_mode=parse_mode, + caption_entities=caption_entities, + has_spoiler=has_spoiler, + ttl_seconds=ttl_seconds, + duration=duration, + width=width, + height=height, + thumb=thumb, + file_name=file_name, + supports_streaming=supports_streaming, + disable_notification=disable_notification, + reply_to_story_id=reply_to_story_id, + reply_markup=reply_markup, + progress=progress, + progress_args=progress_args + ) + + async def reply_video_note( + self, + video_note: Union[str, BinaryIO], + duration: int = 0, + length: int = 1, + thumb: Union[str, BinaryIO] = None, + disable_notification: bool = None, + reply_to_story_id: int = None, + reply_markup: Union[ + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" + ] = None, + progress: Callable = None, + progress_args: tuple = () + ) -> "types.Message": + """Bound method *reply_video_note* of :obj:`~pyrogram.types.Story`. + + Use as a shortcut for: + + .. code-block:: python + + await client.send_video_note( + chat_id=story.from_user.id, + video_note=video_note, + reply_to_story_id=story.id + ) + + Example: + .. code-block:: python + + await story.reply_video_note(video_note) + + Parameters: + 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. + + duration (``int``, *optional*): + Duration of sent video in seconds. + + length (``int``, *optional*): + Video width and height. + + thumb (``str`` | ``BinaryIO``, *optional*): + Thumbnail of the video sent. + The thumbnail should be in JPEG format and less than 200 KB in size. + A thumbnail's width and height should not exceed 320 pixels. + Thumbnails can't be reused and can be only uploaded as a new file. + + disable_notification (``bool``, *optional*): + Sends the message silently. + Users will receive a notification with no sound. + + reply_to_story_id (``int``, *optional*): + If the message is a reply, ID of the original message + + 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. + + 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, the sent :obj:`~pyrogram.types.Message` is returned. + In case the upload is deliberately stopped with :meth:`~pyrogram.Client.stop_transmission`, None is returned + instead. + + Raises: + RPCError: In case of a Telegram RPC error. + """ + if reply_to_story_id is None: + reply_to_story_id = self.id + + return await self._client.send_video_note( + chat_id=self.chat.id, + video_note=video_note, + duration=duration, + length=length, + thumb=thumb, + disable_notification=disable_notification, + reply_to_story_id=reply_to_story_id, + reply_markup=reply_markup, + progress=progress, + progress_args=progress_args + ) + + async def reply_voice( + self, + voice: Union[str, BinaryIO], + caption: str = "", + parse_mode: Optional["enums.ParseMode"] = None, + caption_entities: List["types.MessageEntity"] = None, + duration: int = 0, + disable_notification: bool = None, + reply_to_story_id: int = None, + reply_markup: Union[ + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" + ] = None, + progress: Callable = None, + progress_args: tuple = () + ) -> "types.Message": + """Bound method *reply_voice* of :obj:`~pyrogram.types.Story`. + + Use as a shortcut for: + + .. code-block:: python + + await client.send_voice( + chat_id=story.from_user.id, + voice=voice, + reply_to_story_id=story.id + ) + + Example: + .. code-block:: python + + await message.reply_voice(voice) + + Parameters: + 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. + + caption (``str``, *optional*): + Voice message caption, 0-1024 characters. + + 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*. + + duration (``int``, *optional*): + Duration of the voice message in seconds. + + disable_notification (``bool``, *optional*): + Sends the message silently. + Users will receive a notification with no sound. + + reply_to_story_id (``int``, *optional*): + If the message is a reply, ID of the original message + + 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. + + 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, the sent :obj:`~pyrogram.types.Message` is returned. + In case the upload is deliberately stopped with :meth:`~pyrogram.Client.stop_transmission`, None is returned + instead. + + Raises: + RPCError: In case of a Telegram RPC error. + """ + if reply_to_story_id is None: + reply_to_story_id = self.id + + return await self._client.send_voice( + chat_id=self.chat.id, + voice=voice, + caption=caption, + parse_mode=parse_mode, + caption_entities=caption_entities, + duration=duration, + disable_notification=disable_notification, + reply_to_story_id=reply_to_story_id, + reply_markup=reply_markup, + progress=progress, + progress_args=progress_args + ) + + async def delete(self): + """Bound method *delete* of :obj:`~pyrogram.types.Story`. + + Use as a shortcut for: + + .. code-block:: python + + await client.delete_stories( + story_ids=story.id + ) + + Example: + .. code-block:: python + + await story.delete() + + Returns: + True on success, False otherwise. + + Raises: + RPCError: In case of a Telegram RPC error. + """ + return await self._client.delete_stories(story_ids=self.id) + + async def edit_animation( + self, + animation: Union[str, BinaryIO] + ) -> "types.Story": + """Bound method *edit_animation* of :obj:`~pyrogram.types.Story`. + + Use as a shortcut for: + + .. code-block:: python + + await client.edit_animation( + story_id=story.id, + animation="/path/to/animation.mp4" + ) + + Example: + .. code-block:: python + + await story.edit_animation("/path/to/animation.mp4") + + Parameters: + animation (``str`` | ``BinaryIO``): + New animation of the story. + + Returns: + On success, the edited :obj:`~pyrogram.types.Story` is returned. + + Raises: + RPCError: In case of a Telegram RPC error. + """ + return await self._client.edit_story( + story_id=self.id, + animation=animation + ) + + async def edit( + self, + privacy: "enums.StoriesPrivacy" = None, + allowed_users: List[int] = None, + denied_users: List[int] = None, + allowed_chats: List[int] = None, + denied_chats: List[int] = None, + animation: str = None, + photo: str = None, + video: str = None, + caption: str = None, + parse_mode: "enums.ParseMode" = None, + caption_entities: List["types.MessageEntity"] = None + ) -> "types.Story": + """Bound method *edit* of :obj:`~pyrogram.types.Story`. + + Use as a shortcut for: + + .. code-block:: python + + await client.edit_story( + story_id=story.id, + caption="hello" + ) + + Example: + .. code-block:: python + + await story.edit_caption("hello") + + Parameters: + story_id (``int``): + Unique identifier (int) of the target story. + + animation (``str`` | ``BinaryIO``, *optional*): + New story Animation. + Pass a file_id as string to send a animation that exists on the Telegram servers, + pass an HTTP URL as a string for Telegram to get a animation from the Internet, + pass a file path as string to upload a new animation that exists on your local machine, or + pass a binary file-like object with its attribute ".name" set for in-memory uploads. + + photo (``str`` | ``BinaryIO``, *optional*): + New story photo. + 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, + 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. + + video (``str`` | ``BinaryIO``, *optional*): + New story video. + 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, + 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. + + privacy (:obj:`~pyrogram.enums.StoriesPrivacy`, *optional*): + Story privacy. + + allowed_chats (List of ``int``, *optional*): + List of chat_id which participant allowed to view the story. + + denied_chats (List of ``int``, *optional*): + List of chat_id which participant denied to view the story. + + allowed_users (List of ``int``, *optional*): + List of user_id whos allowed to view the story. + + denied_users (List of ``int``, *optional*): + List of user_id whos denied to view the story. + + caption (``str``, *optional*): + Story caption, 0-1024 characters. + + 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*. + + Returns: + On success, the edited :obj:`~pyrogram.types.Story` is returned. + + Raises: + RPCError: In case of a Telegram RPC error. + """ + return await self._client.edit_story( + story_id=self.id, + privacy=privacy, + allowed_chats=allowed_chats, + denied_chats=denied_chats, + allowed_users=allowed_users, + denied_users=denied_users, + animation=animation, + photo=photo, + video=video, + caption=caption, + parse_mode=parse_mode, + caption_entities=caption_entities + ) + + async def edit_caption( + self, + caption: str, + parse_mode: Optional["enums.ParseMode"] = None, + caption_entities: List["types.MessageEntity"] = None + ) -> "types.Story": + """Bound method *edit_caption* of :obj:`~pyrogram.types.Story`. + + Use as a shortcut for: + + .. code-block:: python + + await client.edit_story( + story_id=story.id, + caption="hello" + ) + + Example: + .. code-block:: python + + await story.edit_caption("hello") + + Parameters: + caption (``str``): + New caption of the story. + + 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*. + + Returns: + On success, the edited :obj:`~pyrogram.types.Story` is returned. + + Raises: + RPCError: In case of a Telegram RPC error. + """ + return await self._client.edit_story( + story_id=self.id, + caption=caption, + parse_mode=parse_mode, + caption_entities=caption_entities + ) + + async def edit_photo( + self, + photo: Union[str, BinaryIO] + ) -> "types.Story": + """Bound method *edit_photo* of :obj:`~pyrogram.types.Story`. + + Use as a shortcut for: + + .. code-block:: python + + await client.edit_story( + story_id=story.id, + photo="/path/to/photo.png" + ) + + Example: + .. code-block:: python + + await story.edit_photo("/path/to/photo.png") + + Parameters: + photo (``str`` | ``BinaryIO``): + New photo of the story. + + Returns: + On success, the edited :obj:`~pyrogram.types.Story` is returned. + + Raises: + RPCError: In case of a Telegram RPC error. + """ + return await self._client.edit_story( + story_id=self.id, + photo=photo + ) + + async def edit_privacy( + self, + privacy: "enums.StoriesPrivacy" = None, + allowed_users: List[int] = None, + denied_users: List[int] = None, + allowed_chats: List[int] = None, + denied_chats: List[int] = None + ) -> "types.Story": + """Bound method *edit_privacy* of :obj:`~pyrogram.types.Story`. + + Use as a shortcut for: + + .. code-block:: python + + await client.edit_story( + story_id=story.id, + privacy=enums.StoriesPrivacy.PUBLIC + ) + + Example: + .. code-block:: python + + await story.edit_privacy(enums.StoriesPrivacy.PUBLIC) + + Parameters: + privacy (:obj:`~pyrogram.enums.StoriesPrivacy`, *optional*): + Story privacy. + + allowed_chats (List of ``int``, *optional*): + List of chat_id which participant allowed to view the story. + + denied_chats (List of ``int``, *optional*): + List of chat_id which participant denied to view the story. + + allowed_users (List of ``int``, *optional*): + List of user_id whos allowed to view the story. + + denied_users (List of ``int``, *optional*): + List of user_id whos denied to view the story. + + Returns: + On success, the edited :obj:`~pyrogram.types.Story` is returned. + + Raises: + RPCError: In case of a Telegram RPC error. + """ + return await self._client.edit_story( + story_id=self.id, + privacy=privacy, + allowed_chats=allowed_chats, + denied_chats=denied_chats, + allowed_users=allowed_users, + denied_users=denied_users + ) + + async def edit_video( + self, + video: Union[str, BinaryIO] + ) -> "types.Story": + """Bound method *edit_video* of :obj:`~pyrogram.types.Story`. + + Use as a shortcut for: + + .. code-block:: python + + await client.edit_story( + story_id=story.id, + video="/path/to/video.mp4" + ) + + Example: + .. code-block:: python + + await story.edit_video("/path/to/video.mp4") + + Parameters: + video (``str`` | ``BinaryIO``): + New video of the story. + + Returns: + On success, the edited :obj:`~pyrogram.types.Story` is returned. + + Raises: + RPCError: In case of a Telegram RPC error. + """ + return await self._client.edit_story( + story_id=self.id, + video=video + ) + + async def export_link(self) -> "types.ExportedStoryLink": + """Bound method *export_link* of :obj:`~pyrogram.types.Story`. + + Use as a shortcut for: + + .. code-block:: python + + await client.export_story_link( + user_id=story.from_user.id, + story_id=story.id + ) + + Example: + .. code-block:: python + + await story.export_link() + + Returns: + :obj:`~pyrogram.types.ExportedStoryLink`: a single story link is returned. + + Raises: + RPCError: In case of a Telegram RPC error. + """ + return await self._client.export_story_link(user_id=self.from_user.id, story_id=self.id) diff --git a/pyrogram/types/messages_and_media/story_views.py b/pyrogram/types/messages_and_media/story_views.py new file mode 100644 index 00000000..662636a9 --- /dev/null +++ b/pyrogram/types/messages_and_media/story_views.py @@ -0,0 +1,50 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2022-present Mayuri-Chan +# +# This file is part of Pyrofork. +# +# Pyrofork 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. +# +# Pyrofork 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 Pyrofork. If not, see . + +from pyrogram import raw +from typing import List +from ..object import Object + +class StoryViews(Object): + """Contains information about a story viewers. + + + Parameters: + view_count (``int``): + The count of stories viewers. + + recent_viewers (List of ``int``): + List of user_id of recent stories viewers. + """ + + def __init__( + self, *, + view_count: int, + recent_viewers: List[int] = None + ): + super().__init__() + + self.view_count = view_count + self.recent_viewers = recent_viewers + + @staticmethod + def _parse(storyviews: "raw.types.StoryViews") -> "StoryViews": + return StoryViews( + view_count=getattr(storyviews,"view_count", None), + recent_viewers=getattr(storyviews,"recent_viewers", None) + )