diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 024fedc6..610f640b 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -315,6 +315,10 @@ def pyrogram_api(): Payments check_gift_code """, + phone=""" + Phone + get_call_members + """, password=""" Password enable_cloud_password @@ -461,6 +465,7 @@ def pyrogram_api(): Restriction EmojiStatus Folder + GroupCallMember ChatColor """, messages_media=""" diff --git a/pyrogram/methods/__init__.py b/pyrogram/methods/__init__.py index 1c14cfa4..bcf4ebe0 100644 --- a/pyrogram/methods/__init__.py +++ b/pyrogram/methods/__init__.py @@ -27,6 +27,7 @@ from .invite_links import InviteLinks from .messages import Messages from .password import Password from .payments import Payments +from .phone import Phone from .premium import Premium from .users import Users from .stories import Stories @@ -41,6 +42,7 @@ class Methods( Contacts, Password, Payments, + Phone, Premium, Chats, Users, diff --git a/pyrogram/methods/phone/__init__.py b/pyrogram/methods/phone/__init__.py new file mode 100644 index 00000000..d2cff63d --- /dev/null +++ b/pyrogram/methods/phone/__init__.py @@ -0,0 +1,25 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from .get_call_members import GetCallMembers + + +class Phone( + GetCallMembers +): + pass diff --git a/pyrogram/methods/phone/get_call_members.py b/pyrogram/methods/phone/get_call_members.py new file mode 100644 index 00000000..8fabc1d9 --- /dev/null +++ b/pyrogram/methods/phone/get_call_members.py @@ -0,0 +1,103 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from typing import Union, AsyncGenerator + +import pyrogram +from pyrogram import types, raw + + +class GetCallMembers: + async def get_call_members( + self: "pyrogram.Client", + chat_id: Union[int, str], + limit: int = 0 + ) -> AsyncGenerator["types.GroupCallMember", None]: + """Get the members list of a chat call. + + A chat can be either a basic group or a supergroup. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + chat_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the target chat. + + limit (``int``, *optional*): + Limits the number of members to be retrieved. + + Returns: + ``Generator``: On success, a generator yielding :obj:`~pyrogram.types.GroupCallMember` objects is returned. + + Example: + .. code-block:: python + + # Get members + async for member in app.get_call_members(chat_id): + print(member) + """ + peer = await self.resolve_peer(chat_id) + + if isinstance(peer, raw.types.InputPeerChannel): + r = await self.invoke(raw.functions.channels.GetFullChannel(channel=peer)) + elif isinstance(peer, raw.types.InputPeerChat): + r = await self.invoke(raw.functions.messages.GetFullChat(chat_id=peer.chat_id)) + else: + raise ValueError("Target chat should be group, supergroup or channel.") + + full_chat = r.full_chat + + if not getattr(full_chat, "call", None): + raise ValueError("There is no active call in this chat.") + + current = 0 + offset = "" + total = abs(limit) or (1 << 31) - 1 + limit = min(20, total) + + while True: + r = await self.invoke( + raw.functions.phone.GetGroupParticipants( + call=full_chat.call, + ids=[], + sources=[], + offset=offset, + limit=limit + ), + sleep_threshold=60 + ) + + users = {u.id: u for u in r.users} + chats = {c.id: c for c in r.chats} + members = [ + types.GroupCallMember._parse(self, member, users, chats) + for member in r.participants + ] + + if not members: + return + + offset = r.next_offset + + for member in members: + yield member + + current += 1 + + if current >= total: + return diff --git a/pyrogram/types/user_and_chats/__init__.py b/pyrogram/types/user_and_chats/__init__.py index 938dcaf3..e5126ac7 100644 --- a/pyrogram/types/user_and_chats/__init__.py +++ b/pyrogram/types/user_and_chats/__init__.py @@ -41,6 +41,7 @@ from .chat_reactions import ChatReactions from .dialog import Dialog from .emoji_status import EmojiStatus from .folder import Folder +from .group_call_member import GroupCallMember from .invite_link_importer import InviteLinkImporter from .restriction import Restriction from .user import User @@ -83,5 +84,6 @@ __all__ = [ "ChatJoiner", "EmojiStatus", "Folder", + "GroupCallMember", "ChatReactions" ] diff --git a/pyrogram/types/user_and_chats/group_call_member.py b/pyrogram/types/user_and_chats/group_call_member.py new file mode 100644 index 00000000..551db102 --- /dev/null +++ b/pyrogram/types/user_and_chats/group_call_member.py @@ -0,0 +1,149 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# 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 Dict + +import pyrogram +from pyrogram import raw, types, utils +from ..object import Object + + +class GroupCallMember(Object): + """Contains information about one member of a group call. + + Parameters: + chat (:obj:`~pyrogram.types.Chat`, *optional*): + Information about the user or chat. + + date (:py:obj:`~datetime.datetime`, *optional*): + Date when this participant join this group call. + + active_date (:py:obj:`~datetime.datetime`, *optional*): + Date when this participant last active in this group call. + + volume (``int``, *optional*): + Volume, if not set the volume is set to 100%. + + can_self_unmute (``bool``, *optional*): + Whether the participant can unmute themselves. + + is_muted (``bool``, *optional*): + Whether the participant is muted. + + is_left (``bool``, *optional*): + Whether the participant has left. + + is_just_joined (``bool``, *optional*): + Whether the participant has just joined. + + is_muted_by_you (``bool``, *optional*): + Whether this participant was muted by the current user. + + is_volume_by_admin (``bool``, *optional*): + Whether our volume can only changed by an admin. + + is_self (``bool``, *optional*): + Whether this participant is the current user. + + is_video_joined (``bool``, *optional*): + Whether this participant is currently broadcasting video. + + is_hand_raised (``bool``, *optional*): + Whether this participant is raised hand. + + is_video_enabled (``bool``, *optional*): + Whether this participant is currently broadcasting video. + + is_screen_sharing_enabled (``bool``, *optional*): + Whether this participant is currently shared screen. + """ + + def __init__( + self, + *, + client: "pyrogram.Client" = None, + chat: "types.Chat" = None, + date: datetime = None, + active_date: datetime = None, + volume: int = None, + can_self_unmute: bool = None, + is_muted: bool = None, + is_left: bool = None, + is_just_joined: bool = None, + is_muted_by_you: bool = None, + is_volume_by_admin: bool = None, + is_self: bool = None, + is_video_joined: bool = None, + is_hand_raised: bool = None, + is_video_enabled: bool = None, + is_screen_sharing_enabled: bool = None + ): + super().__init__(client) + + self.chat = chat + self.date = date + self.active_date = active_date + self.volume = volume + self.can_self_unmute = can_self_unmute + self.is_muted = is_muted + self.is_left = is_left + self.is_just_joined = is_just_joined + self.is_muted_by_you = is_muted_by_you + self.is_volume_by_admin = is_volume_by_admin + self.is_self = is_self + self.is_video_joined = is_video_joined + self.is_hand_raised = is_hand_raised + self.is_video_enabled = is_video_enabled + self.is_screen_sharing_enabled = is_screen_sharing_enabled + + @staticmethod + def _parse( + client: "pyrogram.Client", + member: "raw.types.GroupCallParticipant", + users: Dict[int, "raw.base.User"], + chats: Dict[int, "raw.base.Chat"] + ) -> "GroupCallMember": + peer = member.peer + peer_id = utils.get_raw_peer_id(peer) + + parsed_chat = types.Chat._parse_chat( + client, + users[peer_id] if isinstance(peer, raw.types.PeerUser) else chats[peer_id], + ) + + parsed_chat.bio = getattr(member, "about", None) + + return GroupCallMember( + chat=parsed_chat, + date=utils.timestamp_to_datetime(member.date), + active_date=utils.timestamp_to_datetime(member.active_date), + volume=getattr(member, "volume", None), + can_self_unmute=member.can_self_unmute, + is_muted=member.muted, + is_left=member.left, + is_just_joined=member.just_joined, + is_muted_by_you=member.muted_by_you, + is_volume_by_admin=member.volume_by_admin, + is_self=member.is_self, + is_video_joined=member.video_joined, + is_hand_raised=bool(getattr(member, "raise_hand_rating", None)), + is_video_enabled=bool(getattr(member, "video", None)), + is_screen_sharing_enabled=bool(getattr(member, "presentation", None)), + client=client + )