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
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
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

View File

@ -17,12 +17,12 @@
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
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
)

View File

@ -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
)