diff --git a/pyrogram/methods/users/get_chat_photos.py b/pyrogram/methods/users/get_chat_photos.py index 05dfd92d..64e56cee 100644 --- a/pyrogram/methods/users/get_chat_photos.py +++ b/pyrogram/methods/users/get_chat_photos.py @@ -16,6 +16,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . +from datetime import datetime from typing import Union, AsyncGenerator, Optional import pyrogram @@ -27,7 +28,12 @@ class GetChatPhotos: self: "pyrogram.Client", chat_id: Union[int, str], limit: int = 0, - ) -> AsyncGenerator["types.Photo", None]: + ) -> Optional[ + Union[ + AsyncGenerator["types.Photo", None], + AsyncGenerator["types.Animation", None] + ] + ]: """Get a chat or a user profile photos sequentially. .. include:: /_includes/usable-by/users-bots.rst @@ -43,7 +49,7 @@ class GetChatPhotos: By default, no limit is applied and all profile photos are returned. Returns: - ``Generator``: A generator yielding :obj:`~pyrogram.types.Photo` objects. + ``Generator``: A generator yielding :obj:`~pyrogram.types.Photo` | :obj:`~pyrogram.types.Animation` objects. Example: .. code-block:: python @@ -60,39 +66,45 @@ class GetChatPhotos: ) ) - current = types.Photo._parse(self, r.full_chat.chat_photo) or [] - - r = await utils.parse_messages( + current = types.Animation._parse_chat_animation( self, - await self.invoke( - raw.functions.messages.Search( - peer=peer_id, - q="", - filter=raw.types.InputMessagesFilterChatPhotos(), - min_date=0, - max_date=0, - offset_id=0, - add_offset=0, - limit=limit, - max_id=0, - min_id=0, - hash=0 + r.full_chat.chat_photo, + f"photo_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.mp4" + ) or types.Photo._parse(self, r.full_chat.chat_photo) or [] + current = [current] + + if not self.me.is_bot: + r = await utils.parse_messages( + self, + await self.invoke( + raw.functions.messages.Search( + peer=peer_id, + q="", + filter=raw.types.InputMessagesFilterChatPhotos(), + min_date=0, + max_date=0, + offset_id=0, + add_offset=0, + limit=limit, + max_id=0, + min_id=0, + hash=0 + ) ) ) - ) - extra = [message.new_chat_photo for message in r] + extra = [message.new_chat_photo for message in r] - if extra: - if current: - photos = ([current] + extra) if current.file_id != extra[0].file_id else extra + if extra: + if current: + photos = (current + extra) if current[0].file_id != extra[0].file_id else extra + else: + photos = extra else: - photos = extra - else: - if current: - photos = [current] - else: - photos = [] + if current: + photos = current + else: + photos = [] current = 0 @@ -119,7 +131,14 @@ class GetChatPhotos: ) ) - photos = [types.Photo._parse(self, photo) for photo in r.photos] + photos = [ + types.Animation._parse_chat_animation( + self, + photo, + f"photo_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.mp4" + ) or types.Photo._parse(self, photo) + for photo in r.photos + ] if not photos: return diff --git a/pyrogram/types/messages_and_media/animation.py b/pyrogram/types/messages_and_media/animation.py index 1e7bf4cf..fa735e75 100644 --- a/pyrogram/types/messages_and_media/animation.py +++ b/pyrogram/types/messages_and_media/animation.py @@ -17,12 +17,12 @@ # along with Pyrogram. If not, see . from datetime import datetime -from typing import List +from typing import List, Optional import pyrogram from pyrogram import raw, utils from pyrogram import types -from pyrogram.file_id import FileId, FileType, FileUniqueId, FileUniqueType +from pyrogram.file_id import FileId, FileType, FileUniqueId, FileUniqueType, ThumbnailSource from ..object import Object @@ -99,7 +99,7 @@ class Animation(Object): ) -> "Animation": return Animation( file_id=FileId( - file_type=FileType.ANIMATION, + file_type=FileType.PHOTO, dc_id=animation.dc_id, media_id=animation.id, access_hash=animation.access_hash, @@ -119,3 +119,50 @@ class Animation(Object): thumbs=types.Thumbnail._parse(client, animation), client=client ) + + @staticmethod + def _parse_chat_animation( + client, + video: "raw.types.Photo", + file_name: str + ) -> Optional["Animation"]: + if isinstance(video, raw.types.Photo): + if not video.video_sizes: + return None + + videos: List[raw.types.VideoSize] = [] + + for v in video.video_sizes: + if isinstance(v, raw.types.VideoSize): + videos.append(v) + + videos.sort(key=lambda v: v.size) + + main = videos[-1] + + return Animation( + file_id=FileId( + file_type=FileType.PHOTO, + dc_id=video.dc_id, + media_id=video.id, + access_hash=video.access_hash, + file_reference=video.file_reference, + thumbnail_source=ThumbnailSource.THUMBNAIL, + thumbnail_file_type=FileType.PHOTO, + thumbnail_size=main.type, + volume_id=0, + local_id=0 + ).encode(), + file_unique_id=FileUniqueId( + file_unique_type=FileUniqueType.DOCUMENT, + media_id=video.id + ).encode(), + width=main.w, + height=main.h, + duration=0, + file_size=main.size, + date=utils.timestamp_to_datetime(video.date), + file_name=file_name, + mime_type="video/mp4", + client=client + ) diff --git a/pyrogram/types/user_and_chats/chat_photo.py b/pyrogram/types/user_and_chats/chat_photo.py index b3aba61d..4e73b34a 100644 --- a/pyrogram/types/user_and_chats/chat_photo.py +++ b/pyrogram/types/user_and_chats/chat_photo.py @@ -43,6 +43,12 @@ class ChatPhoto(Object): big_photo_unique_id (``str``): Unique file identifier of big (640x640) chat photo, which is supposed to be the same over time and for different accounts. Can't be used to download or reuse the file. + + has_animation (``bool``): + True, if animated profile picture is available for this user. + + is_personal (``bool``): + True, if the photo is visible only for the current user. """ def __init__( @@ -52,8 +58,9 @@ class ChatPhoto(Object): small_file_id: str, small_photo_unique_id: str, big_file_id: str, - big_photo_unique_id: str - + big_photo_unique_id: str, + has_animation: bool, + is_personal: bool ): super().__init__(client) @@ -61,6 +68,8 @@ class ChatPhoto(Object): self.small_photo_unique_id = small_photo_unique_id self.big_file_id = big_file_id self.big_photo_unique_id = big_photo_unique_id + self.has_animation = has_animation + self.is_personal = is_personal @staticmethod def _parse( @@ -103,5 +112,7 @@ class ChatPhoto(Object): file_unique_type=FileUniqueType.DOCUMENT, media_id=chat_photo.photo_id ).encode(), + has_animation=chat_photo.has_video, + is_personal=getattr(chat_photo, "personal", False), client=client )