Add support for animated chat photos in get_chat_photos

This commit is contained in:
KurimuzonAkuma 2024-08-26 19:31:51 +03:00
parent 1d08f33f72
commit 1d92c09d44
3 changed files with 112 additions and 35 deletions

View File

@ -16,6 +16,7 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from datetime import datetime
from typing import Union, AsyncGenerator, Optional from typing import Union, AsyncGenerator, Optional
import pyrogram import pyrogram
@ -27,7 +28,12 @@ class GetChatPhotos:
self: "pyrogram.Client", self: "pyrogram.Client",
chat_id: Union[int, str], chat_id: Union[int, str],
limit: int = 0, 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. """Get a chat or a user profile photos sequentially.
.. include:: /_includes/usable-by/users-bots.rst .. 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. By default, no limit is applied and all profile photos are returned.
Returns: Returns:
``Generator``: A generator yielding :obj:`~pyrogram.types.Photo` objects. ``Generator``: A generator yielding :obj:`~pyrogram.types.Photo` | :obj:`~pyrogram.types.Animation` objects.
Example: Example:
.. code-block:: python .. code-block:: python
@ -60,8 +66,14 @@ class GetChatPhotos:
) )
) )
current = types.Photo._parse(self, r.full_chat.chat_photo) or [] current = types.Animation._parse_chat_animation(
self,
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( r = await utils.parse_messages(
self, self,
await self.invoke( await self.invoke(
@ -85,12 +97,12 @@ class GetChatPhotos:
if extra: if extra:
if current: 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: else:
photos = extra photos = extra
else: else:
if current: if current:
photos = [current] photos = current
else: else:
photos = [] photos = []
@ -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: if not photos:
return return

View File

@ -17,12 +17,12 @@
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from datetime import datetime from datetime import datetime
from typing import List from typing import List, Optional
import pyrogram import pyrogram
from pyrogram import raw, utils from pyrogram import raw, utils
from pyrogram import types 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 from ..object import Object
@ -99,7 +99,7 @@ class Animation(Object):
) -> "Animation": ) -> "Animation":
return Animation( return Animation(
file_id=FileId( file_id=FileId(
file_type=FileType.ANIMATION, file_type=FileType.PHOTO,
dc_id=animation.dc_id, dc_id=animation.dc_id,
media_id=animation.id, media_id=animation.id,
access_hash=animation.access_hash, access_hash=animation.access_hash,
@ -119,3 +119,50 @@ class Animation(Object):
thumbs=types.Thumbnail._parse(client, animation), thumbs=types.Thumbnail._parse(client, animation),
client=client 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
)

View File

@ -43,6 +43,12 @@ class ChatPhoto(Object):
big_photo_unique_id (``str``): big_photo_unique_id (``str``):
Unique file identifier of big (640x640) chat photo, which is supposed to be the same over time and for 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. 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__( def __init__(
@ -52,8 +58,9 @@ class ChatPhoto(Object):
small_file_id: str, small_file_id: str,
small_photo_unique_id: str, small_photo_unique_id: str,
big_file_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) super().__init__(client)
@ -61,6 +68,8 @@ class ChatPhoto(Object):
self.small_photo_unique_id = small_photo_unique_id self.small_photo_unique_id = small_photo_unique_id
self.big_file_id = big_file_id self.big_file_id = big_file_id
self.big_photo_unique_id = big_photo_unique_id self.big_photo_unique_id = big_photo_unique_id
self.has_animation = has_animation
self.is_personal = is_personal
@staticmethod @staticmethod
def _parse( def _parse(
@ -103,5 +112,7 @@ class ChatPhoto(Object):
file_unique_type=FileUniqueType.DOCUMENT, file_unique_type=FileUniqueType.DOCUMENT,
media_id=chat_photo.photo_id media_id=chat_photo.photo_id
).encode(), ).encode(),
has_animation=chat_photo.has_video,
is_personal=getattr(chat_photo, "personal", False),
client=client client=client
) )