diff --git a/pyrogram/methods/users/get_chat_photos.py b/pyrogram/methods/users/get_chat_photos.py index 890d1845..765aa4c1 100644 --- a/pyrogram/methods/users/get_chat_photos.py +++ b/pyrogram/methods/users/get_chat_photos.py @@ -28,7 +28,12 @@ class GetChatPhotos: self: "pyrogram.Client", chat_id: Union[int, str], limit: int = 0, - ) -> Optional[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 @@ -45,7 +50,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.Video` objects. Example: .. code-block:: python @@ -63,36 +68,44 @@ class GetChatPhotos: ) current = types.Photo._parse(self, r.full_chat.chat_photo) or [] - - r = await utils.parse_messages( + current = [current] + current_animation = 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 + ) + if current_animation: + current = current + [current_animation] + extra = [] + 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 + photos = (current + extra) if current[0].file_id != extra[0].file_id else extra else: photos = extra else: if current: - photos = [current] + photos = current else: photos = [] @@ -121,7 +134,17 @@ class GetChatPhotos: ) ) - photos = [types.Photo._parse(self, photo) for photo in r.photos] + photos = [] + for photo in r.photos: + photos.append( + types.Photo._parse(self, photo) + ) + current_animation = types.Animation._parse_chat_animation( + self, + photo + ) + if current_animation: + photos.append(current_animation) if not photos: return diff --git a/pyrogram/types/messages_and_media/animation.py b/pyrogram/types/messages_and_media/animation.py index a9b7ddc7..3502ac4c 100644 --- a/pyrogram/types/messages_and_media/animation.py +++ b/pyrogram/types/messages_and_media/animation.py @@ -44,7 +44,7 @@ class Animation(Object): height (``int``): Animation height as defined by sender. - duration (``int``): + duration (``int``, *optional*): Duration of the animation in seconds as defined by sender. file_name (``str``, *optional*): @@ -71,7 +71,7 @@ class Animation(Object): file_unique_id: str, width: int, height: int, - duration: int, + duration: int = None, file_name: str = None, mime_type: str = None, file_size: int = None, @@ -120,3 +120,44 @@ class Animation(Object): thumbs=types.Thumbnail._parse(client, animation), client=client ) + + @staticmethod + def _parse_chat_animation( + client, + video: "raw.types.Photo" + ) -> "Animation": + if isinstance(video, raw.types.Photo): + if not video.video_sizes: + return + video_sizes: List[raw.types.VideoSize] = [] + for p in video.video_sizes: + if isinstance(p, raw.types.VideoSize): + video_sizes.append(p) + # TODO: VideoSizeEmojiMarkup + video_sizes.sort(key=lambda p: p.size) + video_size = video_sizes[-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=video_size.type, + volume_id=0, + local_id=0 + ).encode() if video else None, + file_unique_id=FileUniqueId( + file_unique_type=FileUniqueType.DOCUMENT, + media_id=video.id + ).encode() if video else None, + width=video_size.w, + height=video_size.h, + file_size=video_size.size, + date=utils.timestamp_to_datetime(video.date) if video else None, + file_name=f"chat_video_{video.date}_{client.rnd_id()}.mp4", + mime_type="video/mp4", + client=client + ) diff --git a/pyrogram/types/messages_and_media/video.py b/pyrogram/types/messages_and_media/video.py index 6d4d843e..3d0b6161 100644 --- a/pyrogram/types/messages_and_media/video.py +++ b/pyrogram/types/messages_and_media/video.py @@ -23,7 +23,7 @@ from typing import List 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 diff --git a/pyrogram/types/user_and_chats/chat_photo.py b/pyrogram/types/user_and_chats/chat_photo.py index d9580e02..232df5fa 100644 --- a/pyrogram/types/user_and_chats/chat_photo.py +++ b/pyrogram/types/user_and_chats/chat_photo.py @@ -20,7 +20,7 @@ from typing import Union import pyrogram -from pyrogram import raw +from pyrogram import raw, types from pyrogram.file_id import FileId, FileType, FileUniqueId, FileUniqueType, ThumbnailSource from ..object import Object @@ -44,6 +44,16 @@ 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 the photo has animated variant + + is_personal (``bool``): + True, if the photo is visible only for the current user + + minithumbnail (:obj:`~pyrogram.types.StrippedThumbnail`, *optional*): + User profile photo minithumbnail; may be None. + """ def __init__( @@ -53,8 +63,10 @@ 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, + minithumbnail: "types.StrippedThumbnail" = None ): super().__init__(client) @@ -62,6 +74,9 @@ 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 + self.minithumbnail = minithumbnail @staticmethod def _parse( @@ -104,5 +119,10 @@ 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), + minithumbnail=types.StrippedThumbnail( + data=chat_photo.stripped_thumb + ) if chat_photo.stripped_thumb else None, client=client )