diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 75186890..eb14c257 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -350,7 +350,9 @@ def pyrogram_api(): can_send_story copy_story delete_stories - edit_story + edit_story_caption + edit_story_media + edit_story_privacy export_story_link forward_story get_all_stories @@ -671,7 +673,7 @@ def pyrogram_api(): Story.reply_video_note Story.reply_voice Story.delete - Story.edit + Story.edit_media Story.edit_caption Story.edit_privacy Story.export_link diff --git a/pyrogram/methods/stories/__init__.py b/pyrogram/methods/stories/__init__.py index 9f50a968..870889c5 100644 --- a/pyrogram/methods/stories/__init__.py +++ b/pyrogram/methods/stories/__init__.py @@ -19,7 +19,9 @@ from .can_send_story import CanSendStory from .copy_story import CopyStory from .delete_stories import DeleteStories -from .edit_story import EditStory +from .edit_story_caption import EditStoryCaption +from .edit_story_media import EditStoryMedia +from .edit_story_privacy import EditStoryPrivacy from .export_story_link import ExportStoryLink from .forward_story import ForwardStory from .get_all_stories import GetAllStories @@ -37,7 +39,9 @@ class Stories( CanSendStory, CopyStory, DeleteStories, - EditStory, + EditStoryCaption, + EditStoryMedia, + EditStoryPrivacy, ExportStoryLink, ForwardStory, GetAllStories, diff --git a/pyrogram/methods/stories/edit_story_caption.py b/pyrogram/methods/stories/edit_story_caption.py new file mode 100644 index 00000000..211ca0d3 --- /dev/null +++ b/pyrogram/methods/stories/edit_story_caption.py @@ -0,0 +1,83 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from typing import List, Union + +import pyrogram +from pyrogram import enums, raw, types, utils + +class EditStoryCaption: + async def edit_story_caption( + self: "pyrogram.Client", + chat_id: Union[int, str], + story_id: int, + caption: str, + parse_mode: "enums.ParseMode" = None, + caption_entities: List["types.MessageEntity"] = None, + ) -> "types.Story": + """Edit the caption of story. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + chat_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the target chat. + For your personal cloud (Saved Messages) you can simply use "me" or "self". + + story_id (``int``): + Story identifier in the chat specified in chat_id. + + caption (``str``): + New caption of the story, 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`: On success, the edited story is returned. + + Example: + .. code-block:: python + + await app.edit_story(chat_id, story_id, "new media caption") + """ + + message, entities = (await utils.parse_text_entities(self, caption, parse_mode, caption_entities)).values() + + r = await self.invoke( + raw.functions.stories.EditStory( + peer=await self.resolve_peer(chat_id), + id=story_id, + caption=message, + entities=entities, + ) + ) + + for i in r.updates: + if isinstance(i, raw.types.UpdateStory): + return await types.Story._parse( + self, + i.story, + {i.id: i for i in r.users}, + {i.id: i for i in r.chats}, + i.peer + ) diff --git a/pyrogram/methods/stories/edit_story.py b/pyrogram/methods/stories/edit_story_media.py similarity index 50% rename from pyrogram/methods/stories/edit_story.py rename to pyrogram/methods/stories/edit_story_media.py index 6b1cee19..70a0f301 100644 --- a/pyrogram/methods/stories/edit_story.py +++ b/pyrogram/methods/stories/edit_story_media.py @@ -17,34 +17,28 @@ # along with Pyrogram. If not, see . import os -from typing import List, Union, BinaryIO, Callable +from typing import Union, BinaryIO, Callable import pyrogram -from pyrogram import enums, raw, types, utils, StopTransmission +from pyrogram import raw, types, utils, StopTransmission from pyrogram.errors import FilePartMissing -class EditStory: - async def edit_story( +class EditStoryMedia: + async def edit_story_media( self: "pyrogram.Client", chat_id: Union[int, str], story_id: int, media: Union[str, BinaryIO] = None, - caption: str = None, duration: int = 0, width: int = 0, height: int = 0, thumb: Union[str, BinaryIO] = None, supports_streaming: bool = True, file_name: str = None, - privacy: "enums.StoriesPrivacyRules" = None, - allowed_users: List[Union[int, str]] = None, - disallowed_users: List[Union[int, str]] = None, - parse_mode: "enums.ParseMode" = None, - caption_entities: List["types.MessageEntity"] = None, progress: Callable = None, progress_args: tuple = () ) -> "types.Story": - """Edit story. + """Edit story media. .. include:: /_includes/usable-by/users.rst @@ -52,7 +46,9 @@ class EditStory: chat_id (``int`` | ``str``): Unique identifier (int) or username (str) of the target chat. For your personal cloud (Saved Messages) you can simply use "me" or "self". - For a contact that exists in your Telegram address book you can use his phone number (str). + + story_id (``int``): + Story identifier in the chat specified in chat_id. media (``str`` | ``BinaryIO``, *optional*): Video or photo to send. @@ -60,9 +56,6 @@ class EditStory: 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. - caption (``str``, *optional*): - Story caption, 0-1024 characters. - duration (``int``, *optional*): Duration of sent video in seconds. @@ -78,27 +71,6 @@ class EditStory: 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. - privacy (:obj:`~pyrogram.enums.StoriesPrivacyRules`, *optional*): - Story privacy. - - allowed_users (List of ``int``, *optional*): - List of user_id or chat_id of chat users who are allowed to view stories. - Note: chat_id available only with :obj:`~pyrogram.enums.StoriesPrivacyRules.SELECTED_USERS`. - Works with :obj:`~pyrogram.enums.StoriesPrivacyRules.CLOSE_FRIENDS` - and :obj:`~pyrogram.enums.StoriesPrivacyRules.SELECTED_USERS` only - - disallowed_users (List of ``int``, *optional*): - List of user_id whos disallow to view the stories. - Note: Works with :obj:`~pyrogram.enums.StoriesPrivacyRules.PUBLIC` - and :obj:`~pyrogram.enums.StoriesPrivacyRules.CONTACTS` only - - 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*. - 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 @@ -111,58 +83,19 @@ class EditStory: object or a Client instance in order to edit the message with the updated progress status. Returns: - :obj:`~pyrogram.types.Story` a single story is returned. + :obj:`~pyrogram.types.Story`: On success, the edited story is returned. Example: .. code-block:: python - # Edit story in your profile - await app.edit_story("me", "story.png", caption='My new story!') + # Replace the current media with a local photo + await app.edit_story_media(chat_id, story_id, "new_photo.jpg") - # Edit story in channel - await app.edit_story(123456, "story.png", caption='My new story!') - - Raises: - ValueError: In case of invalid arguments. + # Replace the current media with a local video + await app.edit_story_media(chat_id, story_id, "new_video.mp4") """ # TODO: media_areas - message, entities = (await utils.parse_text_entities(self, caption, parse_mode, caption_entities)).values() - - privacy_rules = [] - - if privacy: - if privacy == enums.StoriesPrivacyRules.PUBLIC: - privacy_rules.append(raw.types.InputPrivacyValueAllowAll()) - if disallowed_users: - users = [await self.resolve_peer(user_id) for user_id in disallowed_users] - privacy_rules.append(raw.types.InputPrivacyValueDisallowUsers(users=users)) - elif privacy == enums.StoriesPrivacyRules.CONTACTS: - privacy_rules = [raw.types.InputPrivacyValueAllowContacts()] - if disallowed_users: - users = [await self.resolve_peer(user_id) for user_id in disallowed_users] - privacy_rules.append(raw.types.InputPrivacyValueDisallowUsers(users=users)) - elif privacy == enums.StoriesPrivacyRules.CLOSE_FRIENDS: - privacy_rules = [raw.types.InputPrivacyValueAllowCloseFriends()] - if allowed_users: - users = [await self.resolve_peer(user_id) for user_id in allowed_users] - privacy_rules.append(raw.types.InputPrivacyValueAllowUsers(users=users)) - elif privacy == enums.StoriesPrivacyRules.SELECTED_USERS: - _allowed_users = [] - _allowed_chats = [] - - for user in allowed_users: - peer = await self.resolve_peer(user) - if isinstance(peer, raw.types.InputPeerUser): - _allowed_users.append(peer) - elif isinstance(peer, raw.types.InputPeerChat): - _allowed_chats.append(peer) - - if _allowed_users: - privacy_rules.append(raw.types.InputPrivacyValueAllowUsers(users=_allowed_users)) - if _allowed_chats: - privacy_rules.append(raw.types.InputPrivacyValueAllowChatParticipants(chats=_allowed_chats)) - try: if isinstance(media, str): if os.path.isfile(media): @@ -213,42 +146,6 @@ class EditStory: file=file, ) - privacy_rules = [] - - if privacy: - if privacy == enums.StoriesPrivacyRules.PUBLIC: - privacy_rules.append(raw.types.InputPrivacyValueAllowAll()) - if disallowed_users: - users = [await self.resolve_peer(user_id) for user_id in disallowed_users] - privacy_rules.append(raw.types.InputPrivacyValueDisallowUsers(users=users)) - elif privacy == enums.StoriesPrivacyRules.CONTACTS: - privacy_rules = [raw.types.InputPrivacyValueAllowContacts()] - if disallowed_users: - users = [await self.resolve_peer(user_id) for user_id in disallowed_users] - privacy_rules.append(raw.types.InputPrivacyValueDisallowUsers(users=users)) - elif privacy == enums.StoriesPrivacyRules.CLOSE_FRIENDS: - privacy_rules = [raw.types.InputPrivacyValueAllowCloseFriends()] - if allowed_users: - users = [await self.resolve_peer(user_id) for user_id in allowed_users] - privacy_rules.append(raw.types.InputPrivacyValueAllowUsers(users=users)) - elif privacy == enums.StoriesPrivacyRules.SELECTED_USERS: - _allowed_users = [] - _allowed_chats = [] - - for user in allowed_users: - peer = await self.resolve_peer(user) - if isinstance(peer, raw.types.InputPeerUser): - _allowed_users.append(peer) - elif isinstance(peer, (raw.types.InputPeerChat, raw.types.InputPeerChannel)): - _allowed_chats.append(peer) - - if _allowed_users: - privacy_rules.append(raw.types.InputPrivacyValueAllowUsers(users=_allowed_users)) - if _allowed_chats: - privacy_rules.append(raw.types.InputPrivacyValueAllowChatParticipants(chats=_allowed_chats)) - else: - privacy_rules.append(raw.types.InputPrivacyValueAllowAll()) - while True: try: r = await self.invoke( @@ -256,9 +153,6 @@ class EditStory: peer=await self.resolve_peer(chat_id), id=story_id, media=media, - caption=message, - entities=entities, - privacy_rules=privacy_rules, ) ) except FilePartMissing as e: diff --git a/pyrogram/methods/stories/edit_story_privacy.py b/pyrogram/methods/stories/edit_story_privacy.py new file mode 100644 index 00000000..e8bfa70b --- /dev/null +++ b/pyrogram/methods/stories/edit_story_privacy.py @@ -0,0 +1,128 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +import os +from typing import List, Union + +import pyrogram +from pyrogram import enums, raw, types + +class EditStoryPrivacy: + async def edit_story_privacy( + self: "pyrogram.Client", + chat_id: Union[int, str], + story_id: int, + privacy: "enums.StoriesPrivacyRules" = None, + allowed_users: List[Union[int, str]] = None, + disallowed_users: List[Union[int, str]] = None, + ) -> "types.Story": + """Edit the privacy of story. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + chat_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the target chat. + For your personal cloud (Saved Messages) you can simply use "me" or "self". + For a contact that exists in your Telegram address book you can use his phone number (str). + + story_id (``int``): + Story identifier in the chat specified in chat_id. + + privacy (:obj:`~pyrogram.enums.StoriesPrivacyRules`, *optional*): + Story privacy. + + allowed_users (List of ``int``, *optional*): + List of user_id or chat_id of chat users who are allowed to view stories. + Note: chat_id available only with :obj:`~pyrogram.enums.StoriesPrivacyRules.SELECTED_USERS`. + Works with :obj:`~pyrogram.enums.StoriesPrivacyRules.CLOSE_FRIENDS` + and :obj:`~pyrogram.enums.StoriesPrivacyRules.SELECTED_USERS` only + + disallowed_users (List of ``int``, *optional*): + List of user_id whos disallow to view the stories. + Note: Works with :obj:`~pyrogram.enums.StoriesPrivacyRules.PUBLIC` + and :obj:`~pyrogram.enums.StoriesPrivacyRules.CONTACTS` only + + Returns: + :obj:`~pyrogram.types.Story`: On success, the edited story is returned. + + Example: + .. code-block:: python + + # Edit story privacy to public + await app.edit_story_privacy(chat_id, story_id, enums.StoriesPrivacyRules.PUBLIC) + + # Edit the privacy of the story to allow selected users to view the story + await app.edit_story_privacy(chat_id, story_id, enums.StoriesPrivacyRules.SELECTED_USERS, + allowed_users=[123, 456]) + + """ + privacy_rules = [] + + if privacy: + if privacy == enums.StoriesPrivacyRules.PUBLIC: + privacy_rules.append(raw.types.InputPrivacyValueAllowAll()) + if disallowed_users: + users = [await self.resolve_peer(user_id) for user_id in disallowed_users] + privacy_rules.append(raw.types.InputPrivacyValueDisallowUsers(users=users)) + elif privacy == enums.StoriesPrivacyRules.CONTACTS: + privacy_rules = [raw.types.InputPrivacyValueAllowContacts()] + if disallowed_users: + users = [await self.resolve_peer(user_id) for user_id in disallowed_users] + privacy_rules.append(raw.types.InputPrivacyValueDisallowUsers(users=users)) + elif privacy == enums.StoriesPrivacyRules.CLOSE_FRIENDS: + privacy_rules = [raw.types.InputPrivacyValueAllowCloseFriends()] + if allowed_users: + users = [await self.resolve_peer(user_id) for user_id in allowed_users] + privacy_rules.append(raw.types.InputPrivacyValueAllowUsers(users=users)) + elif privacy == enums.StoriesPrivacyRules.SELECTED_USERS: + _allowed_users = [] + _allowed_chats = [] + + for user in allowed_users: + peer = await self.resolve_peer(user) + if isinstance(peer, raw.types.InputPeerUser): + _allowed_users.append(peer) + elif isinstance(peer, (raw.types.InputPeerChat, raw.types.InputPeerChannel)): + _allowed_chats.append(peer) + + if _allowed_users: + privacy_rules.append(raw.types.InputPrivacyValueAllowUsers(users=_allowed_users)) + if _allowed_chats: + privacy_rules.append(raw.types.InputPrivacyValueAllowChatParticipants(chats=_allowed_chats)) + else: + privacy_rules.append(raw.types.InputPrivacyValueAllowAll()) + + + r = await self.invoke( + raw.functions.stories.EditStory( + peer=await self.resolve_peer(chat_id), + id=story_id, + privacy_rules=privacy_rules, + ) + ) + + for i in r.updates: + if isinstance(i, raw.types.UpdateStory): + return await types.Story._parse( + self, + i.story, + {i.id: i for i in r.users}, + {i.id: i for i in r.chats}, + i.peer + ) diff --git a/pyrogram/types/messages_and_media/story.py b/pyrogram/types/messages_and_media/story.py index 54b10b0a..45399bc9 100644 --- a/pyrogram/types/messages_and_media/story.py +++ b/pyrogram/types/messages_and_media/story.py @@ -1479,15 +1479,9 @@ class Story(Object, Update): """ return await self._client.delete_stories(chat_id=self.chat.id, story_ids=self.id) - async def edit( + async def edit_media( self, media: Union[str, BinaryIO] = None, - privacy: "enums.StoriesPrivacyRules" = None, - allowed_users: List[Union[int, str]] = None, - disallowed_users: List[Union[int, 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`. @@ -1503,12 +1497,9 @@ class Story(Object, Update): Example: .. code-block:: python - await story.edit_caption("hello") + await story.edit_media("new_video.mp4") Parameters: - story_id (``int``): - Unique identifier (int) of the target story. - media (``str`` | ``BinaryIO``, *optional*): New story media. Pass a file_id as string to send a photo that exists on the Telegram servers, @@ -1516,46 +1507,16 @@ class Story(Object, Update): 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. - privacy (:obj:`~pyrogram.enums.StoriesPrivacyRules`, *optional*): - Story privacy. - - allowed_users (List of ``int``, *optional*): - List of user_id or chat_id of chat users who are allowed to view stories. - Note: chat_id available only with :obj:`~pyrogram.enums.StoriesPrivacyRules.SELECTED_USERS`. - Works with :obj:`~pyrogram.enums.StoriesPrivacyRules.CLOSE_FRIENDS` - and :obj:`~pyrogram.enums.StoriesPrivacyRules.SELECTED_USERS` only - - disallowed_users (List of ``int``, *optional*): - List of user_id whos disallow to view the stories. - Note: Works with :obj:`~pyrogram.enums.StoriesPrivacyRules.PUBLIC` - and :obj:`~pyrogram.enums.StoriesPrivacyRules.CONTACTS` only - - 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( + return await self._client.edit_story_media( chat_id=self.chat.id, story_id=self.id, - media=media, - privacy=privacy, - allowed_users=allowed_users, - disallowed_users=disallowed_users, - caption=caption, - parse_mode=parse_mode, - caption_entities=caption_entities + media=media ) async def edit_caption( @@ -1570,7 +1531,7 @@ class Story(Object, Update): .. code-block:: python - await client.edit_story( + await client.edit_story_caption( story_id=story.id, caption="hello" ) @@ -1597,7 +1558,7 @@ class Story(Object, Update): Raises: RPCError: In case of a Telegram RPC error. """ - return await self._client.edit_story( + return await self._client.edit_story_caption( chat_id=self.chat.id, story_id=self.id, caption=caption, @@ -1617,7 +1578,7 @@ class Story(Object, Update): .. code-block:: python - await client.edit_story( + await client.edit_story_privacy( story_id=story.id, privacy=enums.StoriesPrivacyRules.PUBLIC ) @@ -1631,13 +1592,13 @@ class Story(Object, Update): privacy (:obj:`~pyrogram.enums.StoriesPrivacyRules`, *optional*): Story privacy. - allowed_users (List of ``int``, *optional*): + allowed_users (List of ``int`` | ``str``, *optional*): List of user_id or chat_id of chat users who are allowed to view stories. Note: chat_id available only with :obj:`~pyrogram.enums.StoriesPrivacyRules.SELECTED_USERS`. Works with :obj:`~pyrogram.enums.StoriesPrivacyRules.CLOSE_FRIENDS` and :obj:`~pyrogram.enums.StoriesPrivacyRules.SELECTED_USERS` only - disallowed_users (List of ``int``, *optional*): + disallowed_users (List of ``int`` | ``str``, *optional*): List of user_id whos disallow to view the stories. Note: Works with :obj:`~pyrogram.enums.StoriesPrivacyRules.PUBLIC` and :obj:`~pyrogram.enums.StoriesPrivacyRules.CONTACTS` only @@ -1648,7 +1609,7 @@ class Story(Object, Update): Raises: RPCError: In case of a Telegram RPC error. """ - return await self._client.edit_story( + return await self._client.edit_story_privacy( chat_id=self.chat.id, story_id=self.id, privacy=privacy,