py-tgcalls 2.0.6__py3-none-any.whl → 2.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {py_tgcalls-2.0.6.dist-info → py_tgcalls-2.1.0.dist-info}/METADATA +11 -16
- py_tgcalls-2.1.0.dist-info/RECORD +106 -0
- {py_tgcalls-2.0.6.dist-info → py_tgcalls-2.1.0.dist-info}/WHEEL +1 -1
- pytgcalls/__init__.py +2 -0
- pytgcalls/__version__.py +1 -1
- pytgcalls/exceptions.py +7 -24
- pytgcalls/ffmpeg.py +2 -2
- pytgcalls/filters.py +49 -6
- pytgcalls/handlers/handlers_holder.py +1 -1
- pytgcalls/media_devices/__init__.py +6 -2
- pytgcalls/media_devices/device_info.py +8 -15
- pytgcalls/media_devices/input_device.py +11 -0
- pytgcalls/media_devices/media_devices.py +41 -92
- pytgcalls/media_devices/screen_device.py +10 -0
- pytgcalls/media_devices/speaker_device.py +10 -0
- pytgcalls/methods/calls/change_volume_call.py +3 -0
- pytgcalls/methods/calls/get_participants.py +5 -1
- pytgcalls/methods/calls/leave_call.py +3 -1
- pytgcalls/methods/stream/__init__.py +14 -10
- pytgcalls/methods/stream/{mute_stream.py → mute.py} +2 -2
- pytgcalls/methods/stream/{pause_stream.py → pause.py} +2 -2
- pytgcalls/methods/stream/play.py +27 -21
- pytgcalls/methods/stream/record.py +49 -0
- pytgcalls/methods/stream/{resume_stream.py → resume.py} +2 -2
- pytgcalls/methods/stream/send_frame.py +38 -0
- pytgcalls/methods/stream/{played_time.py → time.py} +5 -3
- pytgcalls/methods/stream/{unmute_stream.py → unmute.py} +2 -2
- pytgcalls/methods/utilities/__init__.py +6 -0
- pytgcalls/methods/utilities/call_holder.py +5 -2
- pytgcalls/methods/utilities/join_presentation.py +50 -0
- pytgcalls/methods/utilities/log_retries.py +14 -0
- pytgcalls/methods/utilities/start.py +136 -16
- pytgcalls/methods/utilities/stream_params.py +69 -22
- pytgcalls/methods/utilities/update_sources.py +42 -0
- pytgcalls/mtproto/bridged_client.py +36 -2
- pytgcalls/mtproto/client_cache.py +46 -16
- pytgcalls/mtproto/hydrogram_client.py +72 -23
- pytgcalls/mtproto/mtproto_client.py +32 -4
- pytgcalls/mtproto/pyrogram_client.py +72 -23
- pytgcalls/mtproto/telethon_client.py +97 -33
- pytgcalls/scaffold.py +15 -0
- pytgcalls/types/__init__.py +14 -4
- pytgcalls/types/calls/__init__.py +2 -0
- pytgcalls/types/calls/call.py +5 -3
- pytgcalls/types/calls/call_sources.py +4 -0
- pytgcalls/types/chats/group_call_participant.py +23 -0
- pytgcalls/types/py_object.py +9 -10
- pytgcalls/types/raw/audio_stream.py +3 -3
- pytgcalls/types/raw/stream.py +8 -4
- pytgcalls/types/raw/video_stream.py +5 -4
- pytgcalls/types/stream/__init__.py +14 -4
- pytgcalls/types/stream/device.py +36 -0
- pytgcalls/types/stream/direction.py +25 -0
- pytgcalls/types/stream/external_media.py +8 -0
- pytgcalls/types/stream/frame.py +26 -0
- pytgcalls/types/stream/media_stream.py +178 -107
- pytgcalls/types/stream/record_stream.py +99 -0
- pytgcalls/types/stream/stream_ended.py +32 -0
- pytgcalls/types/stream/stream_frames.py +20 -0
- py_tgcalls-2.0.6.dist-info/RECORD +0 -93
- pytgcalls/media_devices/screen_info.py +0 -45
- pytgcalls/types/stream/stream_audio_ended.py +0 -9
- pytgcalls/types/stream/stream_video_ended.py +0 -9
- {py_tgcalls-2.0.6.dist-info → py_tgcalls-2.1.0.dist-info}/LICENSE +0 -0
- {py_tgcalls-2.0.6.dist-info → py_tgcalls-2.1.0.dist-info}/top_level.txt +0 -0
|
@@ -1,42 +1,89 @@
|
|
|
1
|
+
from pathlib import Path
|
|
1
2
|
from typing import Optional
|
|
3
|
+
from typing import Union
|
|
2
4
|
|
|
3
5
|
from ntgcalls import AudioDescription
|
|
4
6
|
from ntgcalls import MediaDescription
|
|
5
7
|
from ntgcalls import VideoDescription
|
|
6
8
|
|
|
7
|
-
from ...
|
|
9
|
+
from ...media_devices.input_device import InputDevice
|
|
10
|
+
from ...media_devices.speaker_device import SpeakerDevice
|
|
11
|
+
from ...types import RecordStream
|
|
12
|
+
from ...types.raw import AudioStream
|
|
13
|
+
from ...types.raw import Stream
|
|
14
|
+
from ...types.raw import VideoStream
|
|
8
15
|
from ...types.stream.media_stream import MediaStream
|
|
9
16
|
|
|
10
17
|
|
|
11
18
|
class StreamParams:
|
|
12
19
|
@staticmethod
|
|
13
|
-
async def get_stream_params(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
20
|
+
async def get_stream_params(
|
|
21
|
+
stream: Optional[Union[str, Path, InputDevice, Stream]],
|
|
22
|
+
) -> MediaDescription:
|
|
17
23
|
if stream is not None:
|
|
24
|
+
if isinstance(stream, (str, Path, InputDevice)):
|
|
25
|
+
stream = MediaStream(stream)
|
|
18
26
|
if isinstance(stream, MediaStream):
|
|
19
27
|
await stream.check_stream()
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
input=stream.stream_audio.path,
|
|
25
|
-
sample_rate=stream.stream_audio.parameters.bitrate,
|
|
26
|
-
bits_per_sample=16,
|
|
27
|
-
channel_count=stream.stream_audio.parameters.channels,
|
|
28
|
+
elif isinstance(stream, RecordStream):
|
|
29
|
+
raise ValueError(
|
|
30
|
+
'Stream should be an instance of '
|
|
31
|
+
'MediaStream or a raw Stream',
|
|
28
32
|
)
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
return StreamParams._parse_stream_description(stream)
|
|
35
|
+
|
|
36
|
+
@staticmethod
|
|
37
|
+
def _parse_media_description(
|
|
38
|
+
media: Optional[Union[AudioStream, VideoStream]],
|
|
39
|
+
) -> Optional[Union[AudioDescription, VideoDescription]]:
|
|
40
|
+
if media is not None:
|
|
41
|
+
if isinstance(media, AudioStream):
|
|
42
|
+
return AudioDescription(
|
|
43
|
+
media_source=media.media_source,
|
|
44
|
+
input=media.path,
|
|
45
|
+
sample_rate=media.parameters.bitrate,
|
|
46
|
+
channel_count=media.parameters.channels,
|
|
47
|
+
)
|
|
48
|
+
elif isinstance(media, VideoStream):
|
|
49
|
+
return VideoDescription(
|
|
50
|
+
media_source=media.media_source,
|
|
51
|
+
input=media.path,
|
|
52
|
+
width=media.parameters.width,
|
|
53
|
+
height=media.parameters.height,
|
|
54
|
+
fps=media.parameters.frame_rate,
|
|
37
55
|
)
|
|
56
|
+
return None
|
|
38
57
|
|
|
58
|
+
@staticmethod
|
|
59
|
+
def _parse_stream_description(
|
|
60
|
+
stream: Optional[Stream],
|
|
61
|
+
) -> MediaDescription:
|
|
39
62
|
return MediaDescription(
|
|
40
|
-
|
|
41
|
-
|
|
63
|
+
microphone=StreamParams._parse_media_description(
|
|
64
|
+
None if stream is None else stream.microphone,
|
|
65
|
+
),
|
|
66
|
+
speaker=StreamParams._parse_media_description(
|
|
67
|
+
None if stream is None else stream.speaker,
|
|
68
|
+
),
|
|
69
|
+
camera=StreamParams._parse_media_description(
|
|
70
|
+
None if stream is None else stream.camera,
|
|
71
|
+
),
|
|
72
|
+
screen=StreamParams._parse_media_description(
|
|
73
|
+
None if stream is None else stream.screen,
|
|
74
|
+
),
|
|
42
75
|
)
|
|
76
|
+
|
|
77
|
+
@staticmethod
|
|
78
|
+
async def get_record_params(
|
|
79
|
+
stream: Optional[Union[str, Path, Stream, SpeakerDevice]],
|
|
80
|
+
) -> MediaDescription:
|
|
81
|
+
if stream is not None:
|
|
82
|
+
if isinstance(stream, (str, Path, SpeakerDevice)):
|
|
83
|
+
stream = RecordStream(stream)
|
|
84
|
+
if isinstance(stream, MediaStream):
|
|
85
|
+
raise ValueError(
|
|
86
|
+
'Stream should be an instance of '
|
|
87
|
+
'RecordStream or a raw Stream',
|
|
88
|
+
)
|
|
89
|
+
return StreamParams._parse_stream_description(stream) # type: ignore
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from typing import Union
|
|
2
|
+
|
|
3
|
+
from ...mtproto import BridgedClient
|
|
4
|
+
from ...scaffold import Scaffold
|
|
5
|
+
from ...types.calls import CallSources
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class UpdateSources(Scaffold):
|
|
9
|
+
async def _update_sources(
|
|
10
|
+
self,
|
|
11
|
+
chat_id: Union[int, str],
|
|
12
|
+
):
|
|
13
|
+
participants = await self._app.get_group_call_participants(
|
|
14
|
+
chat_id,
|
|
15
|
+
)
|
|
16
|
+
if chat_id not in self._call_sources:
|
|
17
|
+
self._call_sources[chat_id] = CallSources()
|
|
18
|
+
for x in participants:
|
|
19
|
+
if x.video_info is not None and \
|
|
20
|
+
x.user_id not in self._call_sources[chat_id].camera:
|
|
21
|
+
self._call_sources[chat_id].camera[
|
|
22
|
+
x.user_id
|
|
23
|
+
] = x.video_info.endpoint
|
|
24
|
+
await self._binding.add_incoming_video(
|
|
25
|
+
chat_id,
|
|
26
|
+
x.video_info.endpoint,
|
|
27
|
+
x.video_info.sources,
|
|
28
|
+
)
|
|
29
|
+
if x.presentation_info is not None and \
|
|
30
|
+
x.user_id not in self._call_sources[chat_id].presentation:
|
|
31
|
+
self._call_sources[chat_id].presentation[
|
|
32
|
+
x.user_id
|
|
33
|
+
] = x.presentation_info.endpoint
|
|
34
|
+
await self._binding.add_incoming_video(
|
|
35
|
+
chat_id,
|
|
36
|
+
x.presentation_info.endpoint,
|
|
37
|
+
x.presentation_info.sources,
|
|
38
|
+
)
|
|
39
|
+
if x.user_id == BridgedClient.chat_id(
|
|
40
|
+
self._cache_local_peer,
|
|
41
|
+
) and x.muted_by_admin:
|
|
42
|
+
self._need_unmute.add(chat_id)
|
|
@@ -6,6 +6,7 @@ from typing import Optional
|
|
|
6
6
|
|
|
7
7
|
from ntgcalls import Protocol
|
|
8
8
|
from ntgcalls import RTCServer
|
|
9
|
+
from ntgcalls import SsrcGroup
|
|
9
10
|
|
|
10
11
|
from ..handlers import HandlersHolder
|
|
11
12
|
from ..types import GroupCallParticipant
|
|
@@ -29,6 +30,19 @@ class BridgedClient(HandlersHolder):
|
|
|
29
30
|
):
|
|
30
31
|
pass
|
|
31
32
|
|
|
33
|
+
async def join_presentation(
|
|
34
|
+
self,
|
|
35
|
+
chat_id: int,
|
|
36
|
+
json_join: str,
|
|
37
|
+
):
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
async def leave_presentation(
|
|
41
|
+
self,
|
|
42
|
+
chat_id: int,
|
|
43
|
+
):
|
|
44
|
+
pass
|
|
45
|
+
|
|
32
46
|
async def request_call(
|
|
33
47
|
self,
|
|
34
48
|
user_id: int,
|
|
@@ -64,6 +78,7 @@ class BridgedClient(HandlersHolder):
|
|
|
64
78
|
async def discard_call(
|
|
65
79
|
self,
|
|
66
80
|
chat_id: int,
|
|
81
|
+
is_missed: bool,
|
|
67
82
|
):
|
|
68
83
|
pass
|
|
69
84
|
|
|
@@ -97,8 +112,9 @@ class BridgedClient(HandlersHolder):
|
|
|
97
112
|
self,
|
|
98
113
|
chat_id: int,
|
|
99
114
|
muted_status: Optional[bool],
|
|
100
|
-
|
|
101
|
-
|
|
115
|
+
video_paused: Optional[bool],
|
|
116
|
+
video_stopped: Optional[bool],
|
|
117
|
+
presentation_paused: Optional[bool],
|
|
102
118
|
participant: Any,
|
|
103
119
|
):
|
|
104
120
|
pass
|
|
@@ -128,6 +144,21 @@ class BridgedClient(HandlersHolder):
|
|
|
128
144
|
def package_name(obj):
|
|
129
145
|
return str(obj.__class__.__module__).split('.')[0]
|
|
130
146
|
|
|
147
|
+
@staticmethod
|
|
148
|
+
def parse_source(source) -> Optional[GroupCallParticipant.SourceInfo]:
|
|
149
|
+
if not source:
|
|
150
|
+
return None
|
|
151
|
+
return GroupCallParticipant.SourceInfo(
|
|
152
|
+
source.endpoint,
|
|
153
|
+
[
|
|
154
|
+
SsrcGroup(
|
|
155
|
+
source_group.semantics,
|
|
156
|
+
[(ssrc & 0xFFFFFFFF) for ssrc in source_group.sources],
|
|
157
|
+
)
|
|
158
|
+
for source_group in source.source_groups
|
|
159
|
+
],
|
|
160
|
+
)
|
|
161
|
+
|
|
131
162
|
@staticmethod
|
|
132
163
|
def parse_participant(participant):
|
|
133
164
|
return GroupCallParticipant(
|
|
@@ -143,6 +174,9 @@ class BridgedClient(HandlersHolder):
|
|
|
143
174
|
if participant.volume is not None else 100,
|
|
144
175
|
bool(participant.just_joined),
|
|
145
176
|
bool(participant.left),
|
|
177
|
+
participant.source,
|
|
178
|
+
BridgedClient.parse_source(participant.video),
|
|
179
|
+
BridgedClient.parse_source(participant.presentation),
|
|
146
180
|
)
|
|
147
181
|
|
|
148
182
|
@staticmethod
|
|
@@ -46,23 +46,52 @@ class ClientCache:
|
|
|
46
46
|
pass
|
|
47
47
|
return None
|
|
48
48
|
|
|
49
|
-
def
|
|
49
|
+
def set_participants_cache_call(
|
|
50
50
|
self,
|
|
51
51
|
input_id: int,
|
|
52
52
|
participant: GroupCallParticipant,
|
|
53
53
|
) -> Optional[GroupCallParticipant]:
|
|
54
54
|
chat_id = self.get_chat_id(input_id)
|
|
55
55
|
if chat_id is not None:
|
|
56
|
-
|
|
57
|
-
ParticipantList
|
|
58
|
-
] = self._call_participants_cache.get(
|
|
56
|
+
return self._internal_set_participants_cache(
|
|
59
57
|
chat_id,
|
|
58
|
+
participant,
|
|
60
59
|
)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
return None
|
|
61
|
+
|
|
62
|
+
def set_participants_cache_chat(
|
|
63
|
+
self,
|
|
64
|
+
chat_id: int,
|
|
65
|
+
call_id: int,
|
|
66
|
+
participant: GroupCallParticipant,
|
|
67
|
+
) -> Optional[GroupCallParticipant]:
|
|
68
|
+
if self._call_participants_cache.get(chat_id) is None:
|
|
69
|
+
self._call_participants_cache.put(
|
|
70
|
+
chat_id,
|
|
71
|
+
ParticipantList(
|
|
72
|
+
call_id,
|
|
73
|
+
),
|
|
74
|
+
)
|
|
75
|
+
return self._internal_set_participants_cache(
|
|
76
|
+
chat_id,
|
|
77
|
+
participant,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
def _internal_set_participants_cache(
|
|
81
|
+
self,
|
|
82
|
+
chat_id: int,
|
|
83
|
+
participant: GroupCallParticipant,
|
|
84
|
+
) -> Optional[GroupCallParticipant]:
|
|
85
|
+
participants: Optional[
|
|
86
|
+
ParticipantList
|
|
87
|
+
] = self._call_participants_cache.get(
|
|
88
|
+
chat_id,
|
|
89
|
+
)
|
|
90
|
+
if participants is not None:
|
|
91
|
+
participants.last_mtproto_update = (
|
|
92
|
+
int(time()) + self._cache_duration
|
|
93
|
+
)
|
|
94
|
+
return participants.update_participant(participant)
|
|
66
95
|
return None
|
|
67
96
|
|
|
68
97
|
async def get_participant_list(
|
|
@@ -90,7 +119,7 @@ class ClientCache:
|
|
|
90
119
|
input_call,
|
|
91
120
|
)
|
|
92
121
|
for participant in list_participants:
|
|
93
|
-
self.
|
|
122
|
+
self.set_participants_cache_call(
|
|
94
123
|
input_call.id,
|
|
95
124
|
participant,
|
|
96
125
|
)
|
|
@@ -122,12 +151,13 @@ class ClientCache:
|
|
|
122
151
|
input_call,
|
|
123
152
|
self._cache_duration,
|
|
124
153
|
)
|
|
125
|
-
self._call_participants_cache.
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
154
|
+
if self._call_participants_cache.get(chat_id) is None:
|
|
155
|
+
self._call_participants_cache.put(
|
|
156
|
+
chat_id,
|
|
157
|
+
ParticipantList(
|
|
158
|
+
input_call.id,
|
|
159
|
+
),
|
|
160
|
+
)
|
|
131
161
|
|
|
132
162
|
def drop_cache(
|
|
133
163
|
self,
|
|
@@ -19,7 +19,9 @@ from hydrogram.raw.functions.phone import EditGroupCallParticipant
|
|
|
19
19
|
from hydrogram.raw.functions.phone import GetGroupCall
|
|
20
20
|
from hydrogram.raw.functions.phone import GetGroupParticipants
|
|
21
21
|
from hydrogram.raw.functions.phone import JoinGroupCall
|
|
22
|
+
from hydrogram.raw.functions.phone import JoinGroupCallPresentation
|
|
22
23
|
from hydrogram.raw.functions.phone import LeaveGroupCall
|
|
24
|
+
from hydrogram.raw.functions.phone import LeaveGroupCallPresentation
|
|
23
25
|
from hydrogram.raw.functions.phone import RequestCall
|
|
24
26
|
from hydrogram.raw.functions.phone import SendSignalingData
|
|
25
27
|
from hydrogram.raw.types import Channel
|
|
@@ -41,6 +43,7 @@ from hydrogram.raw.types import PhoneCall
|
|
|
41
43
|
from hydrogram.raw.types import PhoneCallAccepted
|
|
42
44
|
from hydrogram.raw.types import PhoneCallDiscarded
|
|
43
45
|
from hydrogram.raw.types import PhoneCallDiscardReasonHangup
|
|
46
|
+
from hydrogram.raw.types import PhoneCallDiscardReasonMissed
|
|
44
47
|
from hydrogram.raw.types import PhoneCallProtocol
|
|
45
48
|
from hydrogram.raw.types import PhoneCallRequested
|
|
46
49
|
from hydrogram.raw.types import PhoneCallWaiting
|
|
@@ -86,7 +89,7 @@ class HydrogramClient(BridgedClient):
|
|
|
86
89
|
):
|
|
87
90
|
user_id = self._cache.get_user_id(update.phone_call_id)
|
|
88
91
|
if user_id is not None:
|
|
89
|
-
await self.
|
|
92
|
+
await self._propagate(
|
|
90
93
|
RawCallUpdate(
|
|
91
94
|
user_id,
|
|
92
95
|
RawCallUpdate.Type.SIGNALING_DATA,
|
|
@@ -110,7 +113,7 @@ class HydrogramClient(BridgedClient):
|
|
|
110
113
|
),
|
|
111
114
|
)
|
|
112
115
|
if isinstance(update.phone_call, PhoneCallAccepted):
|
|
113
|
-
await self.
|
|
116
|
+
await self._propagate(
|
|
114
117
|
RawCallUpdate(
|
|
115
118
|
self.user_from_call(update.phone_call),
|
|
116
119
|
RawCallUpdate.Type.ACCEPTED,
|
|
@@ -126,14 +129,14 @@ class HydrogramClient(BridgedClient):
|
|
|
126
129
|
self._cache.drop_phone_call(
|
|
127
130
|
user_id,
|
|
128
131
|
)
|
|
129
|
-
await self.
|
|
132
|
+
await self._propagate(
|
|
130
133
|
ChatUpdate(
|
|
131
134
|
user_id,
|
|
132
135
|
ChatUpdate.Status.DISCARDED_CALL,
|
|
133
136
|
),
|
|
134
137
|
)
|
|
135
138
|
if isinstance(update.phone_call, PhoneCallRequested):
|
|
136
|
-
await self.
|
|
139
|
+
await self._propagate(
|
|
137
140
|
RawCallUpdate(
|
|
138
141
|
self.user_from_call(update.phone_call),
|
|
139
142
|
RawCallUpdate.Type.REQUESTED,
|
|
@@ -144,7 +147,7 @@ class HydrogramClient(BridgedClient):
|
|
|
144
147
|
),
|
|
145
148
|
)
|
|
146
149
|
if isinstance(update.phone_call, PhoneCall):
|
|
147
|
-
await self.
|
|
150
|
+
await self._propagate(
|
|
148
151
|
RawCallUpdate(
|
|
149
152
|
self.user_from_call(update.phone_call),
|
|
150
153
|
RawCallUpdate.Type.CONFIRMED,
|
|
@@ -166,12 +169,12 @@ class HydrogramClient(BridgedClient):
|
|
|
166
169
|
):
|
|
167
170
|
participants = update.participants
|
|
168
171
|
for participant in participants:
|
|
169
|
-
result = self._cache.
|
|
172
|
+
result = self._cache.set_participants_cache_call(
|
|
170
173
|
update.call.id,
|
|
171
174
|
self.parse_participant(participant),
|
|
172
175
|
)
|
|
173
176
|
if result is not None:
|
|
174
|
-
await self.
|
|
177
|
+
await self._propagate(
|
|
175
178
|
UpdatedGroupCallParticipant(
|
|
176
179
|
self._cache.get_chat_id(update.call.id),
|
|
177
180
|
result,
|
|
@@ -199,7 +202,7 @@ class HydrogramClient(BridgedClient):
|
|
|
199
202
|
GroupCallDiscarded,
|
|
200
203
|
):
|
|
201
204
|
self._cache.drop_cache(chat_id)
|
|
202
|
-
await self.
|
|
205
|
+
await self._propagate(
|
|
203
206
|
ChatUpdate(
|
|
204
207
|
chat_id,
|
|
205
208
|
ChatUpdate.Status.CLOSED_VOICE_CHAT,
|
|
@@ -216,7 +219,7 @@ class HydrogramClient(BridgedClient):
|
|
|
216
219
|
ChannelForbidden,
|
|
217
220
|
):
|
|
218
221
|
self._cache.drop_cache(chat_id)
|
|
219
|
-
await self.
|
|
222
|
+
await self._propagate(
|
|
220
223
|
ChatUpdate(
|
|
221
224
|
chat_id,
|
|
222
225
|
ChatUpdate.Status.KICKED,
|
|
@@ -239,7 +242,7 @@ class HydrogramClient(BridgedClient):
|
|
|
239
242
|
update.message.peer_id,
|
|
240
243
|
PeerChat,
|
|
241
244
|
):
|
|
242
|
-
await self.
|
|
245
|
+
await self._propagate(
|
|
243
246
|
ChatUpdate(
|
|
244
247
|
chat_id,
|
|
245
248
|
ChatUpdate.Status.INVITED_VOICE_CHAT,
|
|
@@ -259,7 +262,7 @@ class HydrogramClient(BridgedClient):
|
|
|
259
262
|
ChatForbidden,
|
|
260
263
|
):
|
|
261
264
|
self._cache.drop_cache(chat_id)
|
|
262
|
-
await self.
|
|
265
|
+
await self._propagate(
|
|
263
266
|
ChatUpdate(
|
|
264
267
|
chat_id,
|
|
265
268
|
ChatUpdate.Status.KICKED,
|
|
@@ -287,7 +290,7 @@ class HydrogramClient(BridgedClient):
|
|
|
287
290
|
self._cache.drop_cache(
|
|
288
291
|
chat_id,
|
|
289
292
|
)
|
|
290
|
-
await self.
|
|
293
|
+
await self._propagate(
|
|
291
294
|
ChatUpdate(
|
|
292
295
|
chat_id,
|
|
293
296
|
ChatUpdate.Status.LEFT_GROUP,
|
|
@@ -319,15 +322,22 @@ class HydrogramClient(BridgedClient):
|
|
|
319
322
|
).full_chat.call
|
|
320
323
|
|
|
321
324
|
if input_call is not None:
|
|
322
|
-
|
|
325
|
+
raw_call = (
|
|
323
326
|
await self._app.invoke(
|
|
324
327
|
GetGroupCall(
|
|
325
328
|
call=input_call,
|
|
326
329
|
limit=-1,
|
|
327
330
|
),
|
|
328
331
|
)
|
|
329
|
-
)
|
|
330
|
-
|
|
332
|
+
)
|
|
333
|
+
call: GroupCall = raw_call.call
|
|
334
|
+
participants: List[GroupCallParticipant] = raw_call.participants
|
|
335
|
+
for participant in participants:
|
|
336
|
+
self._cache.set_participants_cache_chat(
|
|
337
|
+
chat_id,
|
|
338
|
+
call.id,
|
|
339
|
+
self.parse_participant(participant),
|
|
340
|
+
)
|
|
331
341
|
if call.schedule_date is not None:
|
|
332
342
|
return None
|
|
333
343
|
|
|
@@ -395,12 +405,12 @@ class HydrogramClient(BridgedClient):
|
|
|
395
405
|
)
|
|
396
406
|
for update in result.updates:
|
|
397
407
|
if isinstance(
|
|
398
|
-
|
|
399
|
-
|
|
408
|
+
update,
|
|
409
|
+
UpdateGroupCallParticipants,
|
|
400
410
|
):
|
|
401
411
|
participants = update.participants
|
|
402
412
|
for participant in participants:
|
|
403
|
-
self._cache.
|
|
413
|
+
self._cache.set_participants_cache_call(
|
|
404
414
|
update.call.id,
|
|
405
415
|
self.parse_participant(participant),
|
|
406
416
|
)
|
|
@@ -409,6 +419,37 @@ class HydrogramClient(BridgedClient):
|
|
|
409
419
|
|
|
410
420
|
return json.dumps({'transport': None})
|
|
411
421
|
|
|
422
|
+
async def join_presentation(
|
|
423
|
+
self,
|
|
424
|
+
chat_id: int,
|
|
425
|
+
json_join: str,
|
|
426
|
+
):
|
|
427
|
+
chat_call = await self._cache.get_full_chat(chat_id)
|
|
428
|
+
if chat_call is not None:
|
|
429
|
+
result: Updates = await self._app.invoke(
|
|
430
|
+
JoinGroupCallPresentation(
|
|
431
|
+
call=chat_call,
|
|
432
|
+
params=DataJSON(data=json_join),
|
|
433
|
+
),
|
|
434
|
+
)
|
|
435
|
+
for update in result.updates:
|
|
436
|
+
if isinstance(update, UpdateGroupCallConnection):
|
|
437
|
+
return update.params.data
|
|
438
|
+
|
|
439
|
+
return json.dumps({'transport': None})
|
|
440
|
+
|
|
441
|
+
async def leave_presentation(
|
|
442
|
+
self,
|
|
443
|
+
chat_id: int,
|
|
444
|
+
):
|
|
445
|
+
chat_call = await self._cache.get_full_chat(chat_id)
|
|
446
|
+
if chat_call is not None:
|
|
447
|
+
await self._app.invoke(
|
|
448
|
+
LeaveGroupCallPresentation(
|
|
449
|
+
call=chat_call,
|
|
450
|
+
),
|
|
451
|
+
)
|
|
452
|
+
|
|
412
453
|
async def request_call(
|
|
413
454
|
self,
|
|
414
455
|
user_id: int,
|
|
@@ -518,15 +559,21 @@ class HydrogramClient(BridgedClient):
|
|
|
518
559
|
async def discard_call(
|
|
519
560
|
self,
|
|
520
561
|
chat_id: int,
|
|
562
|
+
is_missed: bool,
|
|
521
563
|
):
|
|
522
564
|
peer = self._cache.get_phone_call(chat_id)
|
|
523
565
|
if peer is None:
|
|
524
566
|
return
|
|
567
|
+
reason = (
|
|
568
|
+
PhoneCallDiscardReasonMissed()
|
|
569
|
+
if is_missed
|
|
570
|
+
else PhoneCallDiscardReasonHangup()
|
|
571
|
+
)
|
|
525
572
|
await self._app.invoke(
|
|
526
573
|
DiscardCall(
|
|
527
574
|
peer=peer,
|
|
528
575
|
duration=0,
|
|
529
|
-
reason=
|
|
576
|
+
reason=reason,
|
|
530
577
|
connection_id=0,
|
|
531
578
|
video=False,
|
|
532
579
|
),
|
|
@@ -554,8 +601,9 @@ class HydrogramClient(BridgedClient):
|
|
|
554
601
|
self,
|
|
555
602
|
chat_id: int,
|
|
556
603
|
muted_status: Optional[bool],
|
|
557
|
-
|
|
558
|
-
|
|
604
|
+
video_paused: Optional[bool],
|
|
605
|
+
video_stopped: Optional[bool],
|
|
606
|
+
presentation_paused: Optional[bool],
|
|
559
607
|
participant: InputPeer,
|
|
560
608
|
):
|
|
561
609
|
chat_call = await self._cache.get_full_chat(chat_id)
|
|
@@ -565,8 +613,9 @@ class HydrogramClient(BridgedClient):
|
|
|
565
613
|
call=chat_call,
|
|
566
614
|
participant=participant,
|
|
567
615
|
muted=muted_status,
|
|
568
|
-
|
|
569
|
-
|
|
616
|
+
video_paused=video_paused,
|
|
617
|
+
video_stopped=video_stopped,
|
|
618
|
+
presentation_paused=presentation_paused,
|
|
570
619
|
),
|
|
571
620
|
)
|
|
572
621
|
|
|
@@ -69,6 +69,30 @@ class MtProtoClient:
|
|
|
69
69
|
else:
|
|
70
70
|
raise InvalidMTProtoClient()
|
|
71
71
|
|
|
72
|
+
async def join_presentation(
|
|
73
|
+
self,
|
|
74
|
+
chat_id: int,
|
|
75
|
+
json_join: str,
|
|
76
|
+
):
|
|
77
|
+
if self._bind_client is not None:
|
|
78
|
+
return await self._bind_client.join_presentation(
|
|
79
|
+
chat_id,
|
|
80
|
+
json_join,
|
|
81
|
+
)
|
|
82
|
+
else:
|
|
83
|
+
raise InvalidMTProtoClient()
|
|
84
|
+
|
|
85
|
+
async def leave_presentation(
|
|
86
|
+
self,
|
|
87
|
+
chat_id: int,
|
|
88
|
+
):
|
|
89
|
+
if self._bind_client is not None:
|
|
90
|
+
return await self._bind_client.leave_presentation(
|
|
91
|
+
chat_id,
|
|
92
|
+
)
|
|
93
|
+
else:
|
|
94
|
+
raise InvalidMTProtoClient()
|
|
95
|
+
|
|
72
96
|
async def request_call(
|
|
73
97
|
self,
|
|
74
98
|
user_id: int,
|
|
@@ -102,10 +126,12 @@ class MtProtoClient:
|
|
|
102
126
|
async def discard_call(
|
|
103
127
|
self,
|
|
104
128
|
user_id: int,
|
|
129
|
+
is_missed: bool,
|
|
105
130
|
):
|
|
106
131
|
if self._bind_client is not None:
|
|
107
132
|
return await self._bind_client.discard_call(
|
|
108
133
|
user_id,
|
|
134
|
+
is_missed,
|
|
109
135
|
)
|
|
110
136
|
else:
|
|
111
137
|
raise InvalidMTProtoClient()
|
|
@@ -187,16 +213,18 @@ class MtProtoClient:
|
|
|
187
213
|
self,
|
|
188
214
|
chat_id: int,
|
|
189
215
|
muted_status: Optional[bool],
|
|
190
|
-
|
|
191
|
-
|
|
216
|
+
video_paused: Optional[bool],
|
|
217
|
+
video_stopped: Optional[bool],
|
|
218
|
+
presentation_paused: Optional[bool],
|
|
192
219
|
participant: Any,
|
|
193
220
|
):
|
|
194
221
|
if self._bind_client is not None:
|
|
195
222
|
await self._bind_client.set_call_status(
|
|
196
223
|
chat_id,
|
|
197
224
|
muted_status,
|
|
198
|
-
|
|
199
|
-
|
|
225
|
+
video_paused,
|
|
226
|
+
video_stopped,
|
|
227
|
+
presentation_paused,
|
|
200
228
|
participant,
|
|
201
229
|
)
|
|
202
230
|
else:
|