Skip to content

Commit 279d6c7

Browse files
Update set_profile_photo and add set_bot_profile_photo method
1 parent 8aeebfe commit 279d6c7

4 files changed

Lines changed: 225 additions & 34 deletions

File tree

compiler/docs/compiler.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,10 @@ def get_title_list(s: str) -> list:
752752
GiftedStars
753753
GiftedTon
754754
UpgradedGiftAttributeId
755+
InputChatPhoto
756+
InputChatPhotoPrevious
757+
InputChatPhotoStatic
758+
InputChatPhotoAnimation
755759
""",
756760
bot_keyboards="""
757761
Bot keyboards

pyrogram/methods/users/set_profile_photo.py

Lines changed: 103 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,46 +16,32 @@
1616
# You should have received a copy of the GNU Lesser General Public License
1717
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
1818

19-
from typing import Union, BinaryIO, Optional
19+
import logging
20+
from typing import BinaryIO, Optional, Union
2021

2122
import pyrogram
22-
from pyrogram import raw
23+
from pyrogram import raw, types
2324

25+
log = logging.getLogger(__name__)
2426

2527
class SetProfilePhoto:
2628
async def set_profile_photo(
2729
self: "pyrogram.Client",
30+
photo: Optional["types.InputChatPhoto"] = None,
31+
is_public: Optional[bool] = None,
2832
*,
29-
photo: Optional[Union[str, BinaryIO]] = None,
30-
video: Optional[Union[str, BinaryIO]] = None,
31-
is_public: Optional[bool] = None
33+
video: Optional[Union[str, BinaryIO]] = None
3234
) -> bool:
33-
"""Set a new profile photo or video (H.264/MPEG-4 AVC video, max 5 seconds).
34-
35-
The ``photo`` and ``video`` arguments are mutually exclusive.
36-
Pass either one as named argument (see examples below).
37-
38-
.. note::
39-
40-
This method only works for Users.
41-
Bots profile photos must be set using BotFather.
35+
"""Changes a profile photo for the current user.
4236
4337
.. include:: /_includes/usable-by/users.rst
4438
4539
Parameters:
46-
photo (``str`` | ``BinaryIO``, *optional*):
40+
photo (:obj:`~pyrogram.types.InputChatPhoto`, *optional*):
4741
Profile photo to set.
48-
Pass a file path as string to upload a new photo that exists on your local machine or
49-
pass a binary file-like object with its attribute ".name" set for in-memory uploads.
50-
51-
video (``str`` | ``BinaryIO``, *optional*):
52-
Profile video to set.
53-
Pass a file path as string to upload a new video that exists on your local machine or
54-
pass a binary file-like object with its attribute ".name" set for in-memory uploads.
5542
5643
is_public (``bool``, *optional*):
57-
If set to True, the chosen profile photo will be shown to users that can't display
58-
your main profile photo due to your privacy settings.
44+
Pass True to set the public photo, which will be visible even if the main photo is hidden by privacy settings.
5945
6046
Returns:
6147
``bool``: True on success.
@@ -64,21 +50,104 @@ async def set_profile_photo(
6450
.. code-block:: python
6551
6652
# Set a new profile photo
67-
await app.set_profile_photo(photo="new_photo.jpg")
53+
await app.set_profile_photo(photo=types.InputChatPhotoStatic("new_photo.jpg"))
6854
6955
# Set a new profile video
70-
await app.set_profile_photo(video="new_video.mp4")
56+
await app.set_profile_photo(photo=types.InputChatPhotoAnimation("new_video.mp4"))
57+
58+
# Set a previous profile photo
59+
await app.set_profile_photo(photo=types.InputChatPhotoPrevious(file_id))
7160
7261
# Set/update your account's public profile photo
73-
await app.set_profile_photo(photo="new_photo.jpg", is_public=True)
62+
await app.set_profile_photo(photo=types.InputChatPhotoStatic("new_photo.jpg"), is_public=True)
7463
"""
64+
if video is not None:
65+
log.warning(
66+
"`video` is deprecated and will be removed in future updates. Use `photo` instead."
67+
)
68+
69+
photo = types.InputChatPhotoAnimation(animation=video)
70+
71+
if photo is not None and not isinstance(photo, types.InputChatPhoto):
72+
log.warning(
73+
"You must pass `photo` as `types.InputChatPhoto`. Passing `photo` as a string "
74+
"or binary object is deprecated and will be removed in future updates."
75+
)
76+
77+
photo = types.InputChatPhotoStatic(photo=photo)
78+
79+
if isinstance(photo, types.InputChatPhotoPrevious):
80+
return bool(
81+
await self.invoke(
82+
raw.functions.photos.UpdateProfilePhoto(
83+
fallback=is_public,
84+
id=await photo.write(self),
85+
)
86+
)
87+
)
88+
else:
89+
return bool(
90+
await self.invoke(
91+
raw.functions.photos.UploadProfilePhoto(
92+
fallback=is_public,
93+
file=await photo.write(self) if isinstance(photo, types.InputChatPhotoStatic) else None,
94+
video=await photo.write(self) if isinstance(photo, types.InputChatPhotoAnimation) else None,
95+
video_start_ts=getattr(photo, "main_frame_timestamp", None),
96+
)
97+
)
98+
)
99+
100+
101+
class SetBotProfilePhoto:
102+
async def set_bot_profile_photo(
103+
self: "pyrogram.Client",
104+
bot_user_id: Union[int, str],
105+
photo: Optional["types.InputChatPhoto"] = None,
106+
) -> bool:
107+
"""Changes a profile photo for a bot.
108+
109+
.. include:: /_includes/usable-by/users.rst
110+
111+
Parameters:
112+
bot_user_id (``int`` | ``str``):
113+
Unique identifier (int) or username (str) of the target bot.
114+
115+
photo (:obj:`~pyrogram.types.InputChatPhoto`, *optional*):
116+
Profile photo to set.
117+
Pass None to remove the profile photo.
118+
119+
Returns:
120+
``bool``: True on success.
121+
122+
Example:
123+
.. code-block:: python
124+
125+
# Set a new bot profile photo
126+
await app.set_bot_profile_photo(bot_user_id="@KurigramBot", photo=types.InputChatPhotoStatic("new_photo.jpg"))
75127
76-
return bool(
77-
await self.invoke(
78-
raw.functions.photos.UploadProfilePhoto(
79-
fallback=is_public,
80-
file=await self.save_file(photo),
81-
video=await self.save_file(video)
128+
# Set a new bot profile video
129+
await app.set_bot_profile_photo(bot_user_id="@KurigramBot", photo=types.InputChatPhotoAnimation("new_video.mp4"))
130+
131+
# Remove bot profile photo
132+
await app.set_bot_profile_photo(bot_user_id="@KurigramBot")
133+
"""
134+
if isinstance(photo, types.InputChatPhotoPrevious):
135+
return bool(
136+
await self.invoke(
137+
raw.functions.photos.UpdateProfilePhoto(
138+
id=await photo.write(self) if photo else raw.types.InputPhotoEmpty(),
139+
bot=await self.resolve_peer(bot_user_id),
140+
)
141+
)
142+
)
143+
else:
144+
return bool(
145+
await self.invoke(
146+
raw.functions.photos.UploadProfilePhoto(
147+
bot=await self.resolve_peer(bot_user_id),
148+
file=await photo.write(self) if isinstance(photo, types.InputChatPhotoStatic) else None,
149+
video=await photo.write(self) if isinstance(photo, types.InputChatPhotoAnimation) else None,
150+
video_start_ts=getattr(photo, "main_frame_timestamp", None),
151+
)
82152
)
83153
)
84-
)

pyrogram/types/input_content/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
# You should have received a copy of the GNU Lesser General Public License
1717
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
1818

19+
from .input_chat_photo import InputChatPhoto, InputChatPhotoPrevious, InputChatPhotoStatic, InputChatPhotoAnimation
1920
from .input_checklist import InputChecklist
2021
from .input_contact_message_content import InputContactMessageContent
2122
from .input_credentials import InputCredentials
@@ -54,6 +55,10 @@
5455
from .input_venue_message_content import InputVenueMessageContent
5556

5657
__all__ = [
58+
"InputChatPhoto",
59+
"InputChatPhotoPrevious",
60+
"InputChatPhotoStatic",
61+
"InputChatPhotoAnimation",
5762
"InputChecklist",
5863
"InputContactMessageContent",
5964
"InputCredentials",
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# Pyrogram - Telegram MTProto API Client Library for Python
2+
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
3+
#
4+
# This file is part of Pyrogram.
5+
#
6+
# Pyrogram is free software: you can redistribute it and/or modify
7+
# it under the terms of the GNU Lesser General Public License as published
8+
# by the Free Software Foundation, either version 3 of the License, or
9+
# (at your option) any later version.
10+
#
11+
# Pyrogram is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
# GNU Lesser General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU Lesser General Public License
17+
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
18+
19+
from typing import BinaryIO, Optional, Union
20+
21+
import pyrogram
22+
from pyrogram import raw, utils
23+
from pyrogram.file_id import FileType
24+
25+
from ..object import Object
26+
27+
28+
class InputChatPhoto(Object):
29+
"""Describes a photo to be set as a user profile or chat photo.
30+
31+
It should be one of:
32+
33+
- :obj:`~pyrogram.types.InputChatPhotoPrevious`
34+
- :obj:`~pyrogram.types.InputChatPhotoStatic`
35+
- :obj:`~pyrogram.types.InputChatPhotoAnimation`
36+
"""
37+
# TODO: - :obj:`~pyrogram.types.InputChatPhotoSticker`
38+
39+
def __init__(
40+
self,
41+
):
42+
super().__init__()
43+
44+
async def write(self, client: "pyrogram.Client") -> "raw.base.InputFile":
45+
raise NotImplementedError
46+
47+
48+
class InputChatPhotoPrevious(InputChatPhoto):
49+
"""A previously used profile photo of the current user.
50+
51+
Parameters:
52+
chat_photo_file_id (``str``):
53+
Identifier of the current user's profile photo to reuse.
54+
"""
55+
def __init__(
56+
self,
57+
chat_photo_file_id: int
58+
):
59+
super().__init__()
60+
61+
self.chat_photo_file_id = chat_photo_file_id
62+
63+
async def write(self, client: "pyrogram.Client") -> "raw.types.InputPhoto":
64+
photo = utils.get_input_media_from_file_id(self.chat_photo_file_id, FileType.PHOTO)
65+
66+
return photo.id
67+
68+
69+
class InputChatPhotoStatic(InputChatPhoto):
70+
"""A static photo in JPEG format.
71+
72+
Parameters:
73+
photo (``str`` | ``BinaryIO``):
74+
Photo to be set as profile photo.
75+
"""
76+
def __init__(
77+
self,
78+
photo: Union[str, BinaryIO]
79+
):
80+
super().__init__()
81+
82+
self.photo = photo
83+
84+
async def write(self, client: "pyrogram.Client") -> "raw.base.InputFile":
85+
return await client.save_file(self.photo)
86+
87+
88+
class InputChatPhotoAnimation(InputChatPhoto):
89+
"""An animation in H.264/MPEG-4 AVC format.
90+
91+
.. note::
92+
93+
Must be square, at most 10 seconds long, have width between 160 and 1280 and be at most 2MB in size
94+
95+
Parameters:
96+
animation (``str`` | ``BinaryIO``):
97+
Animation to be set as profile photo.
98+
99+
main_frame_timestamp (``float``):
100+
Timestamp of the frame, which will be used as static chat photo.
101+
"""
102+
def __init__(
103+
self,
104+
animation: Union[str, BinaryIO],
105+
main_frame_timestamp: Optional[float] = None
106+
):
107+
super().__init__()
108+
109+
self.animation = animation
110+
self.main_frame_timestamp = main_frame_timestamp
111+
112+
async def write(self, client: "pyrogram.Client") -> "raw.base.InputFile":
113+
return await client.save_file(self.animation)

0 commit comments

Comments
 (0)