py-tgcalls 2.2.0rc1__py3-none-any.whl → 2.2.0rc3__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: py-tgcalls
3
- Version: 2.2.0rc1
3
+ Version: 2.2.0rc3
4
4
  Summary: Async client API for the Telegram Calls.
5
5
  Author-email: Laky-64 <iraci.matteo@gmail.com>
6
6
  Project-URL: Homepage, https://pytgcalls.github.io/
@@ -20,7 +20,7 @@ Requires-Python: >=3.9
20
20
  Description-Content-Type: text/markdown
21
21
  License-File: LICENSE
22
22
  Requires-Dist: aiohttp>=3.9.3
23
- Requires-Dist: ntgcalls<3.0.0,>=2.0.0rc1
23
+ Requires-Dist: ntgcalls<3.0.0,>=2.0.0rc5
24
24
  Requires-Dist: deprecation
25
25
  Provides-Extra: pyrogram
26
26
  Requires-Dist: pyrogram>=1.2.20; extra == "pyrogram"
@@ -1,10 +1,10 @@
1
- py_tgcalls-2.2.0rc1.dist-info/licenses/LICENSE,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
1
+ py_tgcalls-2.2.0rc3.dist-info/licenses/LICENSE,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
2
2
  pytgcalls/__init__.py,sha256=qbfwN7rYwIdCegMOzdcbvwazeNjDzgmowgcqLFNqKIM,308
3
- pytgcalls/__version__.py,sha256=jo4muqb6qG7eUqrTQ9ReKjcC5myNMlrB6VPZVMqXPWE,25
3
+ pytgcalls/__version__.py,sha256=oggK25XEBVcFHD0dtA1CXYnNjf3ynxvgKwJFaniQ3Is,25
4
4
  pytgcalls/environment.py,sha256=ctCHACvG6l8SdpPewSBhOvc70kbwpv18maC0TwLvZ08,1924
5
5
  pytgcalls/exceptions.py,sha256=Rijc-8T93WEWJxNW9jncU8_M6mYZZZcs8F2bqitEIeI,3787
6
6
  pytgcalls/ffmpeg.py,sha256=CZvSyuztc-TGKbKI9_2G7CLITe1ITf315YPyprWu_Pg,8645
7
- pytgcalls/filters.py,sha256=qTFDlt-23xnMh_Ug2WmmOUf13JPX6_yacrv7c3F9Pp0,6125
7
+ pytgcalls/filters.py,sha256=8Fq_gvHHdqhIk_XwMJ9wneeZOwrvBkSOKaMJ60r3bZU,6157
8
8
  pytgcalls/list_to_cmd.py,sha256=rGJLsejbAQdDb8pctMbLnwea5NkitlfVKc3IpoGi4V4,240
9
9
  pytgcalls/mtproto_required.py,sha256=6B-31p5qH_6oekUgypV4nK3hqPS6Nr-pA8S81wjnbaY,630
10
10
  pytgcalls/mutex.py,sha256=vWqji9IAHtAc61FUTVXncx5rZ3rVf5qG_7PI4LmuYmU,733
@@ -39,7 +39,7 @@ pytgcalls/methods/internal/clear_call.py,sha256=yElvn3i6_j14Q7n9kcLSl-muYAGcaIZa
39
39
  pytgcalls/methods/internal/connect_call.py,sha256=Py-sB_ImH839tK9GxNUCJDJUNizsZtlm5m6kuiUX3lE,5739
40
40
  pytgcalls/methods/internal/emit_sig_data.py,sha256=ucIsknhJHB-0x7lcymXvwQ647AJQ852zH2W6MdlC3ws,216
41
41
  pytgcalls/methods/internal/handle_connection_changed.py,sha256=_1u3J6_Pjl1Gs1u_WkhG2FAUl_hxlHUiflaMkKkJDsc,866
42
- pytgcalls/methods/internal/handle_mtproto_updates.py,sha256=Ev2Jake6Z_SrBodnjO5N16YiYaEY3Ti4tkU1pKOsJVM,7747
42
+ pytgcalls/methods/internal/handle_mtproto_updates.py,sha256=Kt5ioQ-qYHNIwzEwLLsNJBG-INA4vk21t01zCzpy7k0,7722
43
43
  pytgcalls/methods/internal/handle_stream_ended.py,sha256=DllD1ZfGQbwVh-S0neocwnN-8lQtwwyrzWl9teSrZbY,561
44
44
  pytgcalls/methods/internal/handle_stream_frame.py,sha256=_FA782qlOT3tUqnySm7RBpjbgfEEzt1oEBDm-iADsbQ,1145
45
45
  pytgcalls/methods/internal/join_presentation.py,sha256=dLB2kolIIm2KQH8yBQbEPJi_y1_cVLWpE52_Rwjn_KE,2178
@@ -70,19 +70,19 @@ pytgcalls/methods/utilities/run.py,sha256=cnYQd2xB5Cr_WS0Q2cXJZPGiN6JOCULzj1r4xX
70
70
  pytgcalls/methods/utilities/start.py,sha256=mn0kQZhTUuc-9CCJDbFIVsEtJ8kfnfZOGbVC505qVRM,3232
71
71
  pytgcalls/methods/utilities/stream_params.py,sha256=fOSloo1A7WTxaZEtOiPXjdexMeoJjq8CZtfHuIFX7Ns,3325
72
72
  pytgcalls/mtproto/__init__.py,sha256=X4zvzFG7km7qHyE0fdvA550WcOVO_xl_p__gvIfDGmw,130
73
- pytgcalls/mtproto/bridged_client.py,sha256=svXufZkCj7WM9XOWkuk5oJVQxgL1Bg_8rz7w_ZKWlQg,6451
74
- pytgcalls/mtproto/client_cache.py,sha256=fpmZhRUGD3G2t2LjEK0z4OPLmWVhJQZUvDW6bgr6StI,5907
75
- pytgcalls/mtproto/hydrogram_client.py,sha256=pSEtHowL833-vD5ppm78eBe7_Ik0pumChbDTMLsyP5Y,25553
73
+ pytgcalls/mtproto/bridged_client.py,sha256=gG69X4tbFKwPiMdBYMEYSSqqB6UcTp1B-HpqqGvOqR4,7005
74
+ pytgcalls/mtproto/client_cache.py,sha256=73o111KTSxGSw1OrG8m4QBnz7VSzETiTLnhEt49IXw0,6595
75
+ pytgcalls/mtproto/hydrogram_client.py,sha256=XKHsyWXJTe5jzo0m-hLxvYaJ_65TOA7W0i4vS3BtxcI,28591
76
76
  pytgcalls/mtproto/mtproto_client.py,sha256=95A13HsNJfpNslsY_gWiqYXj_Vvo-pl3rVrsJGxftgg,8517
77
- pytgcalls/mtproto/pyrogram_client.py,sha256=linvRHAxZCb4PenJEN9-OtjQm7Go9OONyDotZcMydNY,25710
78
- pytgcalls/mtproto/telethon_client.py,sha256=iDMAAKvvFVigOrLPusG9ytiswxM2UCp4KZZuwtT-vKo,24987
77
+ pytgcalls/mtproto/pyrogram_client.py,sha256=5KwGuHC21DjUCe_PVQzLyfxrBuxd2h_xlFPDfX813NU,28588
78
+ pytgcalls/mtproto/telethon_client.py,sha256=6dzPXnfy4_fXjNWjRbH0RrWyD2LTQM3WREfFcBDXwEo,26711
79
79
  pytgcalls/types/__init__.py,sha256=GlgBBXAwbNopXSeTTmiXktrEJhhN_rMBtuAllTBbN3k,1189
80
80
  pytgcalls/types/browsers.py,sha256=47Kr5q96n4Q4WvVhA6IUlS2egEcA9GRLlDeFcQYyc9M,9545
81
81
  pytgcalls/types/cache.py,sha256=FfsOcmYnsBGPlJoTPIXXYcUSpGE3rhx6cjIH77hyUL0,1059
82
82
  pytgcalls/types/dict.py,sha256=lAo9hu4VlVJa9S7P8Y81BYmKtvz0rH7hwpGcH3ynHUw,78
83
83
  pytgcalls/types/flag.py,sha256=dQPcQmTgTQzcOLTvGe8t_e9mY4qsVnCZFrrTk17b2Xw,132
84
84
  pytgcalls/types/list.py,sha256=UjP_XxxMpPkLlu6yEy29JYqOM5VITFwwJcDm0wZni1c,78
85
- pytgcalls/types/participant_list.py,sha256=LmGjU63MK1v3SS2_4xNbk04OOjmukNdAXYLRn2L-730,916
85
+ pytgcalls/types/participant_list.py,sha256=60bDaLQ484qgxk2Mm4cxCtlzqVhUTS7itdfQmuZk4PA,949
86
86
  pytgcalls/types/py_object.py,sha256=__GNXgffGK4jhdF4QPqIknd0k2myObJf_7fW3pNGpbU,836
87
87
  pytgcalls/types/update.py,sha256=wPCzWLhrsScZ3ksRTyt8IuDaaG5YI-ItG_Yw-OqzK2Y,157
88
88
  pytgcalls/types/user_agent.py,sha256=sSfeGqUe0v0wqBgdVszNFK0iOC_0Tdyto9CglBXlY4U,1086
@@ -97,8 +97,8 @@ pytgcalls/types/calls/pending_connection.py,sha256=qRRmutInj70rtzbThM7CNznFhEPqT
97
97
  pytgcalls/types/calls/raw_call_update.py,sha256=hpNw6HrTW8Z36Lh2HinS-wzprryRtsIxyIFbIfjGgeI,795
98
98
  pytgcalls/types/chats/__init__.py,sha256=v8pUp_vbr2kQpyHtAQc80N-YqzmXHe9SbllUsa6njkU,261
99
99
  pytgcalls/types/chats/chat_update.py,sha256=lzrqNDPv4a_yXpKIfUnhocXqZyIy8XgZladOQTYrrYA,730
100
- pytgcalls/types/chats/group_call_participant.py,sha256=XG4dekFV9GYHASqy_bSE6YnZ1uDunFFif-xLAy_eYGY,1711
101
- pytgcalls/types/chats/updated_group_call_participant.py,sha256=-KID-z-4e43fhYWQp0pNMKPfmZizbJHXyzn6yLtIGNg,291
100
+ pytgcalls/types/chats/group_call_participant.py,sha256=alFtJcgK7aGJ6rl4QSmHD2pU3IwDVs0ajV6qInOrf0Q,1481
101
+ pytgcalls/types/chats/updated_group_call_participant.py,sha256=bZQsZAsMv_i4k8DJW3phyuHqpa9Dp6IbheHCvj3M630,365
102
102
  pytgcalls/types/raw/__init__.py,sha256=ROHsKFeUMUtlFbx2rhfrdB-TuVm0zBuvNo29Ccn5614,308
103
103
  pytgcalls/types/raw/audio_parameters.py,sha256=1DsBPwdn_Ukd2Tbkb3whP_ILo9xJY_3XNNmbO4_NO9Q,449
104
104
  pytgcalls/types/raw/audio_stream.py,sha256=oN7Sx9oLbNFuNXiGYpoNabMwqWKGquLiHEywef28o7c,488
@@ -116,7 +116,7 @@ pytgcalls/types/stream/record_stream.py,sha256=f4VQ6MY8HtOxt7vz0hWBFmbbAIvTRHpAI
116
116
  pytgcalls/types/stream/stream_ended.py,sha256=xR_kZwFf03hA6rw_nvI7Be7GwoCKzQf_1MKaGpPDXqY,716
117
117
  pytgcalls/types/stream/stream_frames.py,sha256=028ZhNV-mN3BGqMlmxusAV1xDQpXRYCeM0WXBZhRUhA,446
118
118
  pytgcalls/types/stream/video_quality.py,sha256=HBfWq005kh-D19MaVE9VzVdnODzrXf4IJUimCfslfiU,231
119
- py_tgcalls-2.2.0rc1.dist-info/METADATA,sha256=GjtrQPZp1x1J9YvVAqpqZ_vJVn8428ncuuyi4FVBW0c,5286
120
- py_tgcalls-2.2.0rc1.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
121
- py_tgcalls-2.2.0rc1.dist-info/top_level.txt,sha256=IUDUwn0KkcbUYZbCe9R5AUb2Ob-lmllNUGQqyeXXd8A,10
122
- py_tgcalls-2.2.0rc1.dist-info/RECORD,,
119
+ py_tgcalls-2.2.0rc3.dist-info/METADATA,sha256=xjnla12jR6aBXMOTcFV1k7gNUuQO7Lzdus2L7AX3EbM,5286
120
+ py_tgcalls-2.2.0rc3.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
121
+ py_tgcalls-2.2.0rc3.dist-info/top_level.txt,sha256=IUDUwn0KkcbUYZbCe9R5AUb2Ob-lmllNUGQqyeXXd8A,10
122
+ py_tgcalls-2.2.0rc3.dist-info/RECORD,,
pytgcalls/__version__.py CHANGED
@@ -1 +1 @@
1
- __version__ = '2.2.0rc1'
1
+ __version__ = '2.2.0rc3'
pytgcalls/filters.py CHANGED
@@ -158,6 +158,7 @@ class stream_end(Filter):
158
158
  self.device & update.device
159
159
  )
160
160
  )
161
+ return False
161
162
 
162
163
 
163
164
  # noinspection PyPep8Naming
@@ -190,14 +191,17 @@ class chat_update(Filter):
190
191
 
191
192
  # noinspection PyPep8Naming
192
193
  class call_participant(Filter):
193
- def __init__(self, flags: Optional[GroupCallParticipant.Action] = None):
194
+ def __init__(
195
+ self,
196
+ flags: Optional[GroupCallParticipant.Action] = None,
197
+ ):
194
198
  self.flags = flags
195
199
 
196
200
  async def __call__(self, client: PyTgCalls, update: Update):
197
201
  if isinstance(update, UpdatedGroupCallParticipant):
198
202
  if self.flags is None:
199
203
  return True
200
- return self.flags & update.participant.action
204
+ return self.flags & update.action
201
205
  return False
202
206
 
203
207
 
@@ -72,7 +72,7 @@ class HandleMTProtoUpdates(Scaffold):
72
72
  await self._clear_call(chat_id)
73
73
  if isinstance(update, UpdatedGroupCallParticipant):
74
74
  participant = update.participant
75
- action = participant.action
75
+ action = update.action
76
76
  chat_peer = self._cache_user_peer.get(chat_id)
77
77
  user_id = participant.user_id
78
78
  if chat_id in self._call_sources:
@@ -151,9 +151,9 @@ class HandleMTProtoUpdates(Scaffold):
151
151
  self,
152
152
  )
153
153
  if (
154
- chat_id in self._need_unmute and
155
- action == GroupCallParticipant.Action.UPDATED and
156
- not participant.muted_by_admin
154
+ chat_id in self._need_unmute and
155
+ action == GroupCallParticipant.Action.UPDATED
156
+ and not participant.muted_by_admin
157
157
  ):
158
158
  await self._update_status(
159
159
  chat_id,
@@ -162,8 +162,8 @@ class HandleMTProtoUpdates(Scaffold):
162
162
  await self._switch_connection(chat_id)
163
163
 
164
164
  if (
165
- participant.muted_by_admin and
166
- action != GroupCallParticipant.Action.LEFT
165
+ participant.muted_by_admin and
166
+ action != GroupCallParticipant.Action.LEFT
167
167
  ):
168
168
  self._need_unmute.add(chat_id)
169
169
  else:
@@ -1,4 +1,5 @@
1
1
  import random
2
+ import re
2
3
  from typing import Any
3
4
  from typing import List
4
5
  from typing import Optional
@@ -189,13 +190,20 @@ class BridgedClient(HandlersHolder):
189
190
  bool(participant.raise_hand_rating),
190
191
  participant.volume // 100
191
192
  if participant.volume is not None else 100,
192
- bool(participant.just_joined),
193
- bool(participant.left),
194
193
  participant.source,
195
194
  BridgedClient.parse_source(participant.video),
196
195
  BridgedClient.parse_source(participant.presentation),
197
196
  )
198
197
 
198
+ @staticmethod
199
+ def parse_participant_action(participant):
200
+ if participant.just_joined:
201
+ return GroupCallParticipant.Action.JOINED
202
+ elif participant.left:
203
+ return GroupCallParticipant.Action.LEFT
204
+ else:
205
+ return GroupCallParticipant.Action.UPDATED
206
+
199
207
  @staticmethod
200
208
  def chat_id(input_peer) -> int:
201
209
  class_name = input_peer.__class__.__name__
@@ -260,6 +268,17 @@ class BridgedClient(HandlersHolder):
260
268
  else:
261
269
  return None
262
270
 
271
+ @staticmethod
272
+ def extract_dc(error: str) -> Optional[int]:
273
+ dc_id = re.findall(
274
+ r'('
275
+ r'CALL_MIGRATE_|'
276
+ r'The file to be accessed is currently stored in DC *'
277
+ r')([0-9])',
278
+ error,
279
+ )
280
+ return int(dc_id[0][1]) if dc_id else None
281
+
263
282
  @staticmethod
264
283
  def rnd_id() -> int:
265
284
  return random.randint(0, 0x7FFFFFFF - 1)
@@ -22,6 +22,7 @@ class ClientCache:
22
22
  self._cache_duration = 1 if app.no_updates() else cache_duration
23
23
  self._full_chat_cache = Cache()
24
24
  self._call_participants_cache = Cache()
25
+ self._dc_call_cache = Cache()
25
26
  self._phone_calls = Cache()
26
27
 
27
28
  async def get_full_chat(
@@ -48,12 +49,14 @@ class ClientCache:
48
49
  def set_participants_cache_call(
49
50
  self,
50
51
  input_id: int,
52
+ action: GroupCallParticipant.Action,
51
53
  participant: GroupCallParticipant,
52
54
  ) -> Optional[GroupCallParticipant]:
53
55
  chat_id = self.get_chat_id(input_id)
54
56
  if chat_id is not None:
55
57
  return self._internal_set_participants_cache(
56
58
  chat_id,
59
+ action,
57
60
  participant,
58
61
  )
59
62
  return None
@@ -62,6 +65,7 @@ class ClientCache:
62
65
  self,
63
66
  chat_id: int,
64
67
  call_id: int,
68
+ action: GroupCallParticipant.Action,
65
69
  participant: GroupCallParticipant,
66
70
  ) -> Optional[GroupCallParticipant]:
67
71
  if self._call_participants_cache.get(chat_id) is None:
@@ -73,12 +77,14 @@ class ClientCache:
73
77
  )
74
78
  return self._internal_set_participants_cache(
75
79
  chat_id,
80
+ action,
76
81
  participant,
77
82
  )
78
83
 
79
84
  def _internal_set_participants_cache(
80
85
  self,
81
86
  chat_id: int,
87
+ action: GroupCallParticipant.Action,
82
88
  participant: GroupCallParticipant,
83
89
  ) -> Optional[GroupCallParticipant]:
84
90
  participants: Optional[
@@ -90,7 +96,10 @@ class ClientCache:
90
96
  participants.last_mtproto_update = (
91
97
  int(time()) + self._cache_duration
92
98
  )
93
- return participants.update_participant(participant)
99
+ return participants.update_participant(
100
+ action,
101
+ participant,
102
+ )
94
103
  return None
95
104
 
96
105
  async def get_participant_list(
@@ -120,6 +129,7 @@ class ClientCache:
120
129
  for participant in list_participants:
121
130
  self.set_participants_cache_call(
122
131
  input_call.id,
132
+ GroupCallParticipant.Action.UPDATED,
123
133
  participant,
124
134
  )
125
135
  except Exception as e:
@@ -164,6 +174,23 @@ class ClientCache:
164
174
  ) -> None:
165
175
  self._full_chat_cache.pop(chat_id)
166
176
  self._call_participants_cache.pop(chat_id)
177
+ self._dc_call_cache.pop(chat_id)
178
+
179
+ def set_dc_call(
180
+ self,
181
+ chat_id: int,
182
+ dc_id: int,
183
+ ) -> None:
184
+ self._dc_call_cache.put(
185
+ chat_id,
186
+ dc_id,
187
+ )
188
+
189
+ def get_dc_call(
190
+ self,
191
+ chat_id: int,
192
+ ) -> Optional[int]:
193
+ return self._dc_call_cache.get(chat_id)
167
194
 
168
195
  def set_phone_call(
169
196
  self,
@@ -6,9 +6,14 @@ from typing import Union
6
6
 
7
7
  from hydrogram import Client
8
8
  from hydrogram import ContinuePropagation
9
+ from hydrogram.errors import AuthBytesInvalid
10
+ from hydrogram.errors import BadRequest
11
+ from hydrogram.errors import FileMigrate
9
12
  from hydrogram.errors import FloodWait
10
13
  from hydrogram.raw.base import InputPeer
11
14
  from hydrogram.raw.base import InputUser
15
+ from hydrogram.raw.functions.auth import ExportAuthorization
16
+ from hydrogram.raw.functions.auth import ImportAuthorization
12
17
  from hydrogram.raw.functions.channels import GetFullChannel
13
18
  from hydrogram.raw.functions.messages import GetDhConfig
14
19
  from hydrogram.raw.functions.messages import GetFullChat
@@ -62,6 +67,8 @@ from hydrogram.raw.types import UpdatePhoneCall
62
67
  from hydrogram.raw.types import UpdatePhoneCallSignalingData
63
68
  from hydrogram.raw.types import Updates
64
69
  from hydrogram.raw.types.messages import DhConfig
70
+ from hydrogram.session import Auth
71
+ from hydrogram.session import Session
65
72
  from ntgcalls import MediaSegmentQuality
66
73
  from ntgcalls import Protocol
67
74
 
@@ -87,7 +94,7 @@ class HydrogramClient(BridgedClient):
87
94
  self,
88
95
  )
89
96
 
90
- @self._app.on_raw_update(group=-1)
97
+ @self._app.on_raw_update(group=-9999)
91
98
  async def on_update(_, update, __, chats):
92
99
  if isinstance(
93
100
  update,
@@ -181,14 +188,17 @@ class HydrogramClient(BridgedClient):
181
188
  ):
182
189
  participants = update.participants
183
190
  for participant in participants:
191
+ action = self.parse_participant_action(participant)
184
192
  result = self._cache.set_participants_cache_call(
185
193
  update.call.id,
194
+ action,
186
195
  self.parse_participant(participant),
187
196
  )
188
197
  if result is not None:
189
198
  await self._propagate(
190
199
  UpdatedGroupCallParticipant(
191
200
  self._cache.get_chat_id(update.call.id),
201
+ action,
192
202
  result,
193
203
  ),
194
204
  )
@@ -317,7 +327,7 @@ class HydrogramClient(BridgedClient):
317
327
  chat = await self._app.resolve_peer(chat_id)
318
328
  if isinstance(chat, InputPeerChannel):
319
329
  input_call = (
320
- await self._app.invoke(
330
+ await self._invoke(
321
331
  GetFullChannel(
322
332
  channel=InputChannel(
323
333
  channel_id=chat.channel_id,
@@ -328,14 +338,14 @@ class HydrogramClient(BridgedClient):
328
338
  ).full_chat.call
329
339
  else:
330
340
  input_call = (
331
- await self._app.invoke(
341
+ await self._invoke(
332
342
  GetFullChat(chat_id=chat.chat_id),
333
343
  )
334
344
  ).full_chat.call
335
345
 
336
346
  if input_call is not None:
337
347
  raw_call = (
338
- await self._app.invoke(
348
+ await self._invoke(
339
349
  GetGroupCall(
340
350
  call=input_call,
341
351
  limit=-1,
@@ -348,6 +358,7 @@ class HydrogramClient(BridgedClient):
348
358
  self._cache.set_participants_cache_chat(
349
359
  chat_id,
350
360
  call.id,
361
+ self.parse_participant_action(participant),
351
362
  self.parse_participant(participant),
352
363
  )
353
364
  if call.schedule_date is not None:
@@ -356,7 +367,7 @@ class HydrogramClient(BridgedClient):
356
367
  return input_call
357
368
 
358
369
  async def get_dhc(self) -> DhConfig:
359
- return await self._app.invoke(
370
+ return await self._invoke(
360
371
  GetDhConfig(
361
372
  version=0,
362
373
  random_length=256,
@@ -378,7 +389,7 @@ class HydrogramClient(BridgedClient):
378
389
  participants = []
379
390
  next_offset = ''
380
391
  while True:
381
- result = await self._app.invoke(
392
+ result = await self._invoke(
382
393
  GetGroupParticipants(
383
394
  call=input_call,
384
395
  ids=[],
@@ -405,7 +416,7 @@ class HydrogramClient(BridgedClient):
405
416
  ) -> str:
406
417
  chat_call = await self._cache.get_full_chat(chat_id)
407
418
  if chat_call is not None:
408
- result: Updates = await self._app.invoke(
419
+ result: Updates = await self._invoke(
409
420
  JoinGroupCall(
410
421
  call=chat_call,
411
422
  params=DataJSON(data=json_join),
@@ -424,6 +435,7 @@ class HydrogramClient(BridgedClient):
424
435
  for participant in participants:
425
436
  self._cache.set_participants_cache_call(
426
437
  update.call.id,
438
+ self.parse_participant_action(participant),
427
439
  self.parse_participant(participant),
428
440
  )
429
441
  if isinstance(update, UpdateGroupCallConnection):
@@ -438,7 +450,7 @@ class HydrogramClient(BridgedClient):
438
450
  ):
439
451
  chat_call = await self._cache.get_full_chat(chat_id)
440
452
  if chat_call is not None:
441
- result: Updates = await self._app.invoke(
453
+ result: Updates = await self._invoke(
442
454
  JoinGroupCallPresentation(
443
455
  call=chat_call,
444
456
  params=DataJSON(data=json_join),
@@ -456,7 +468,7 @@ class HydrogramClient(BridgedClient):
456
468
  ):
457
469
  chat_call = await self._cache.get_full_chat(chat_id)
458
470
  if chat_call is not None:
459
- await self._app.invoke(
471
+ await self._invoke(
460
472
  LeaveGroupCallPresentation(
461
473
  call=chat_call,
462
474
  ),
@@ -469,7 +481,7 @@ class HydrogramClient(BridgedClient):
469
481
  protocol: Protocol,
470
482
  has_video: bool,
471
483
  ):
472
- update = await self._app.invoke(
484
+ update = await self._invoke(
473
485
  RequestCall(
474
486
  user_id=await self.resolve_peer(user_id),
475
487
  random_id=self.rnd_id(),
@@ -492,7 +504,7 @@ class HydrogramClient(BridgedClient):
492
504
  g_b: bytes,
493
505
  protocol: Protocol,
494
506
  ):
495
- await self._app.invoke(
507
+ await self._invoke(
496
508
  AcceptCall(
497
509
  peer=self._cache.get_phone_call(user_id),
498
510
  g_b=g_b,
@@ -508,7 +520,7 @@ class HydrogramClient(BridgedClient):
508
520
  protocol: Protocol,
509
521
  ) -> CallProtocol:
510
522
  res = (
511
- await self._app.invoke(
523
+ await self._invoke(
512
524
  ConfirmCall(
513
525
  peer=self._cache.get_phone_call(user_id),
514
526
  g_a=g_a,
@@ -528,7 +540,7 @@ class HydrogramClient(BridgedClient):
528
540
  user_id: int,
529
541
  data: bytes,
530
542
  ):
531
- await self._app.invoke(
543
+ await self._invoke(
532
544
  SendSignalingData(
533
545
  peer=self._cache.get_phone_call(user_id),
534
546
  data=data,
@@ -539,7 +551,7 @@ class HydrogramClient(BridgedClient):
539
551
  self,
540
552
  chat_id: int,
541
553
  ):
542
- result: Updates = await self._app.invoke(
554
+ result: Updates = await self._invoke(
543
555
  CreateGroupCall(
544
556
  peer=await self.resolve_peer(chat_id),
545
557
  random_id=self.rnd_id(),
@@ -569,7 +581,7 @@ class HydrogramClient(BridgedClient):
569
581
  ):
570
582
  chat_call = await self._cache.get_full_chat(chat_id)
571
583
  if chat_call is not None:
572
- await self._app.invoke(
584
+ await self._invoke(
573
585
  LeaveGroupCall(
574
586
  call=chat_call,
575
587
  source=0,
@@ -589,7 +601,7 @@ class HydrogramClient(BridgedClient):
589
601
  if is_missed
590
602
  else PhoneCallDiscardReasonHangup()
591
603
  )
592
- await self._app.invoke(
604
+ await self._invoke(
593
605
  DiscardCall(
594
606
  peer=peer,
595
607
  duration=0,
@@ -608,7 +620,7 @@ class HydrogramClient(BridgedClient):
608
620
  ):
609
621
  chat_call = await self._cache.get_full_chat(chat_id)
610
622
  if chat_call is not None:
611
- await self._app.invoke(
623
+ await self._invoke(
612
624
  EditGroupCallParticipant(
613
625
  call=chat_call,
614
626
  participant=participant,
@@ -629,7 +641,7 @@ class HydrogramClient(BridgedClient):
629
641
  if chat_call is not None:
630
642
  try:
631
643
  return (
632
- await self._app.invoke(
644
+ await self._invoke(
633
645
  GetFile(
634
646
  location=InputGroupCallStream(
635
647
  call=chat_call,
@@ -656,9 +668,8 @@ class HydrogramClient(BridgedClient):
656
668
  ):
657
669
  chat_call = await self._cache.get_full_chat(chat_id)
658
670
  if chat_call is not None:
659
- # noinspection PyBroadException
660
671
  channels = (
661
- await self._app.invoke(
672
+ await self._invoke(
662
673
  GetGroupCallStreamChannels(
663
674
  call=chat_call,
664
675
  ),
@@ -680,7 +691,7 @@ class HydrogramClient(BridgedClient):
680
691
  ):
681
692
  chat_call = await self._cache.get_full_chat(chat_id)
682
693
  if chat_call is not None:
683
- await self._app.invoke(
694
+ await self._invoke(
684
695
  EditGroupCallParticipant(
685
696
  call=chat_call,
686
697
  participant=participant,
@@ -719,5 +730,77 @@ class HydrogramClient(BridgedClient):
719
730
  def no_updates(self):
720
731
  return self._app.no_updates
721
732
 
733
+ async def _invoke(
734
+ self,
735
+ request,
736
+ dc_id: Optional[int] = None,
737
+ chat_id: Optional[int] = None,
738
+ sleep_threshold: Optional[int] = None,
739
+ ):
740
+ if chat_id is not None:
741
+ dc_id = self._cache.get_dc_call(chat_id)
742
+ if dc_id is None:
743
+ session = self._app
744
+ else:
745
+ session = self._app.media_sessions.get(dc_id)
746
+ if not session:
747
+ session = self._app.media_sessions[dc_id] = Session(
748
+ self._app,
749
+ dc_id,
750
+ await Auth(
751
+ self._app,
752
+ dc_id,
753
+ await self._app.storage.test_mode(),
754
+ ).create()
755
+ if dc_id != await self._app.storage.dc_id()
756
+ else await self._app.storage.auth_key(),
757
+ await self._app.storage.test_mode(),
758
+ is_media=True,
759
+ )
760
+ await session.start()
761
+ if dc_id != await self._app.storage.dc_id():
762
+ for _ in range(3):
763
+ exported_auth = await self._invoke(
764
+ ExportAuthorization(
765
+ dc_id=dc_id,
766
+ ),
767
+ )
768
+
769
+ try:
770
+ await session.invoke(
771
+ ImportAuthorization(
772
+ id=exported_auth.id,
773
+ bytes=exported_auth.bytes,
774
+ ),
775
+ )
776
+ except AuthBytesInvalid:
777
+ continue
778
+ else:
779
+ break
780
+ else:
781
+ raise AuthBytesInvalid
782
+ try:
783
+ return await session.invoke(
784
+ request,
785
+ sleep_threshold=sleep_threshold,
786
+ )
787
+ except (BadRequest, FileMigrate) as e:
788
+ dc_new = BridgedClient.extract_dc(
789
+ str(e),
790
+ )
791
+ if dc_new is not None:
792
+ if chat_id is not None:
793
+ self._cache.set_dc_call(
794
+ chat_id,
795
+ dc_new,
796
+ )
797
+ return await self._invoke(
798
+ request,
799
+ dc_new,
800
+ chat_id,
801
+ sleep_threshold,
802
+ )
803
+ raise
804
+
722
805
  async def start(self):
723
806
  await self._app.start()
@@ -4,14 +4,18 @@ from typing import List
4
4
  from typing import Optional
5
5
  from typing import Union
6
6
 
7
- import pyrogram
8
7
  from ntgcalls import MediaSegmentQuality
9
8
  from ntgcalls import Protocol
10
9
  from pyrogram import Client
11
10
  from pyrogram import ContinuePropagation
11
+ from pyrogram.errors import AuthBytesInvalid
12
+ from pyrogram.errors import BadRequest
13
+ from pyrogram.errors import FileMigrate
12
14
  from pyrogram.errors import FloodWait
13
15
  from pyrogram.raw.base import InputPeer
14
16
  from pyrogram.raw.base import InputUser
17
+ from pyrogram.raw.functions.auth import ExportAuthorization
18
+ from pyrogram.raw.functions.auth import ImportAuthorization
15
19
  from pyrogram.raw.functions.channels import GetFullChannel
16
20
  from pyrogram.raw.functions.messages import GetDhConfig
17
21
  from pyrogram.raw.functions.messages import GetFullChat
@@ -65,13 +69,14 @@ from pyrogram.raw.types import UpdatePhoneCall
65
69
  from pyrogram.raw.types import UpdatePhoneCallSignalingData
66
70
  from pyrogram.raw.types import Updates
67
71
  from pyrogram.raw.types.messages import DhConfig
72
+ from pyrogram.session import Auth
73
+ from pyrogram.session import Session
68
74
 
69
75
  from ..types import CallProtocol
70
76
  from ..types import ChatUpdate
71
77
  from ..types import GroupCallParticipant
72
78
  from ..types import RawCallUpdate
73
79
  from ..types import UpdatedGroupCallParticipant
74
- from ..version_manager import VersionManager
75
80
  from .bridged_client import BridgedClient
76
81
  from .client_cache import ClientCache
77
82
 
@@ -84,18 +89,12 @@ class PyrogramClient(BridgedClient):
84
89
  ):
85
90
  super().__init__()
86
91
  self._app: Client = client
87
- if VersionManager.version_tuple(
88
- pyrogram.__version__,
89
- ) > VersionManager.version_tuple(
90
- '2.0.0',
91
- ):
92
- self._app.send = self._app.invoke
93
92
  self._cache: ClientCache = ClientCache(
94
93
  cache_duration,
95
94
  self,
96
95
  )
97
96
 
98
- @self._app.on_raw_update(group=-1)
97
+ @self._app.on_raw_update(group=-9999)
99
98
  async def on_update(_, update, __, chats):
100
99
  if isinstance(
101
100
  update,
@@ -189,17 +188,21 @@ class PyrogramClient(BridgedClient):
189
188
  ):
190
189
  participants = update.participants
191
190
  for participant in participants:
191
+ action = self.parse_participant_action(participant)
192
192
  result = self._cache.set_participants_cache_call(
193
193
  update.call.id,
194
+ action,
194
195
  self.parse_participant(participant),
195
196
  )
196
197
  if result is not None:
197
198
  await self._propagate(
198
199
  UpdatedGroupCallParticipant(
199
200
  self._cache.get_chat_id(update.call.id),
201
+ action,
200
202
  result,
201
203
  ),
202
204
  )
205
+
203
206
  if isinstance(
204
207
  update,
205
208
  UpdateGroupCall,
@@ -325,7 +328,7 @@ class PyrogramClient(BridgedClient):
325
328
  chat = await self._app.resolve_peer(chat_id)
326
329
  if isinstance(chat, InputPeerChannel):
327
330
  input_call = (
328
- await self._app.send(
331
+ await self._invoke(
329
332
  GetFullChannel(
330
333
  channel=InputChannel(
331
334
  channel_id=chat.channel_id,
@@ -336,14 +339,14 @@ class PyrogramClient(BridgedClient):
336
339
  ).full_chat.call
337
340
  else:
338
341
  input_call = (
339
- await self._app.send(
342
+ await self._invoke(
340
343
  GetFullChat(chat_id=chat.chat_id),
341
344
  )
342
345
  ).full_chat.call
343
346
 
344
347
  if input_call is not None:
345
348
  raw_call = (
346
- await self._app.send(
349
+ await self._invoke(
347
350
  GetGroupCall(
348
351
  call=input_call,
349
352
  limit=-1,
@@ -356,6 +359,7 @@ class PyrogramClient(BridgedClient):
356
359
  self._cache.set_participants_cache_chat(
357
360
  chat_id,
358
361
  call.id,
362
+ self.parse_participant_action(participant),
359
363
  self.parse_participant(participant),
360
364
  )
361
365
  if call.schedule_date is not None:
@@ -364,7 +368,7 @@ class PyrogramClient(BridgedClient):
364
368
  return input_call
365
369
 
366
370
  async def get_dhc(self) -> DhConfig:
367
- return await self._app.send(
371
+ return await self._invoke(
368
372
  GetDhConfig(
369
373
  version=0,
370
374
  random_length=256,
@@ -386,7 +390,7 @@ class PyrogramClient(BridgedClient):
386
390
  participants = []
387
391
  next_offset = ''
388
392
  while True:
389
- result = await self._app.send(
393
+ result = await self._invoke(
390
394
  GetGroupParticipants(
391
395
  call=input_call,
392
396
  ids=[],
@@ -413,7 +417,7 @@ class PyrogramClient(BridgedClient):
413
417
  ) -> str:
414
418
  chat_call = await self._cache.get_full_chat(chat_id)
415
419
  if chat_call is not None:
416
- result: Updates = await self._app.send(
420
+ result: Updates = await self._invoke(
417
421
  JoinGroupCall(
418
422
  call=chat_call,
419
423
  params=DataJSON(data=json_join),
@@ -432,6 +436,7 @@ class PyrogramClient(BridgedClient):
432
436
  for participant in participants:
433
437
  self._cache.set_participants_cache_call(
434
438
  update.call.id,
439
+ self.parse_participant_action(participant),
435
440
  self.parse_participant(participant),
436
441
  )
437
442
  if isinstance(update, UpdateGroupCallConnection):
@@ -446,7 +451,7 @@ class PyrogramClient(BridgedClient):
446
451
  ):
447
452
  chat_call = await self._cache.get_full_chat(chat_id)
448
453
  if chat_call is not None:
449
- result: Updates = await self._app.send(
454
+ result: Updates = await self._invoke(
450
455
  JoinGroupCallPresentation(
451
456
  call=chat_call,
452
457
  params=DataJSON(data=json_join),
@@ -464,7 +469,7 @@ class PyrogramClient(BridgedClient):
464
469
  ):
465
470
  chat_call = await self._cache.get_full_chat(chat_id)
466
471
  if chat_call is not None:
467
- await self._app.send(
472
+ await self._invoke(
468
473
  LeaveGroupCallPresentation(
469
474
  call=chat_call,
470
475
  ),
@@ -477,7 +482,7 @@ class PyrogramClient(BridgedClient):
477
482
  protocol: Protocol,
478
483
  has_video: bool,
479
484
  ):
480
- update = await self._app.invoke(
485
+ update = await self._invoke(
481
486
  RequestCall(
482
487
  user_id=await self.resolve_peer(user_id),
483
488
  random_id=self.rnd_id(),
@@ -500,7 +505,7 @@ class PyrogramClient(BridgedClient):
500
505
  g_b: bytes,
501
506
  protocol: Protocol,
502
507
  ):
503
- await self._app.invoke(
508
+ await self._invoke(
504
509
  AcceptCall(
505
510
  peer=self._cache.get_phone_call(user_id),
506
511
  g_b=g_b,
@@ -516,7 +521,7 @@ class PyrogramClient(BridgedClient):
516
521
  protocol: Protocol,
517
522
  ) -> CallProtocol:
518
523
  res = (
519
- await self._app.invoke(
524
+ await self._invoke(
520
525
  ConfirmCall(
521
526
  peer=self._cache.get_phone_call(user_id),
522
527
  g_a=g_a,
@@ -536,7 +541,7 @@ class PyrogramClient(BridgedClient):
536
541
  user_id: int,
537
542
  data: bytes,
538
543
  ):
539
- await self._app.invoke(
544
+ await self._invoke(
540
545
  SendSignalingData(
541
546
  peer=self._cache.get_phone_call(user_id),
542
547
  data=data,
@@ -547,7 +552,7 @@ class PyrogramClient(BridgedClient):
547
552
  self,
548
553
  chat_id: int,
549
554
  ):
550
- result: Updates = await self._app.send(
555
+ result: Updates = await self._invoke(
551
556
  CreateGroupCall(
552
557
  peer=await self.resolve_peer(chat_id),
553
558
  random_id=self.rnd_id(),
@@ -577,7 +582,7 @@ class PyrogramClient(BridgedClient):
577
582
  ):
578
583
  chat_call = await self._cache.get_full_chat(chat_id)
579
584
  if chat_call is not None:
580
- await self._app.send(
585
+ await self._invoke(
581
586
  LeaveGroupCall(
582
587
  call=chat_call,
583
588
  source=0,
@@ -597,7 +602,7 @@ class PyrogramClient(BridgedClient):
597
602
  if is_missed
598
603
  else PhoneCallDiscardReasonHangup()
599
604
  )
600
- await self._app.invoke(
605
+ await self._invoke(
601
606
  DiscardCall(
602
607
  peer=peer,
603
608
  duration=0,
@@ -616,7 +621,7 @@ class PyrogramClient(BridgedClient):
616
621
  ):
617
622
  chat_call = await self._cache.get_full_chat(chat_id)
618
623
  if chat_call is not None:
619
- await self._app.send(
624
+ await self._invoke(
620
625
  EditGroupCallParticipant(
621
626
  call=chat_call,
622
627
  participant=participant,
@@ -637,7 +642,7 @@ class PyrogramClient(BridgedClient):
637
642
  if chat_call is not None:
638
643
  try:
639
644
  return (
640
- await self._app.send(
645
+ await self._invoke(
641
646
  GetFile(
642
647
  location=InputGroupCallStream(
643
648
  call=chat_call,
@@ -651,6 +656,7 @@ class PyrogramClient(BridgedClient):
651
656
  offset=0,
652
657
  limit=limit,
653
658
  ),
659
+ chat_id=chat_id,
654
660
  sleep_threshold=0,
655
661
  )
656
662
  ).bytes
@@ -664,12 +670,12 @@ class PyrogramClient(BridgedClient):
664
670
  ):
665
671
  chat_call = await self._cache.get_full_chat(chat_id)
666
672
  if chat_call is not None:
667
- # noinspection PyBroadException
668
673
  channels = (
669
- await self._app.send(
674
+ await self._invoke(
670
675
  GetGroupCallStreamChannels(
671
676
  call=chat_call,
672
677
  ),
678
+ chat_id=chat_id,
673
679
  )
674
680
  ).channels
675
681
  if len(channels) > 0:
@@ -688,7 +694,7 @@ class PyrogramClient(BridgedClient):
688
694
  ):
689
695
  chat_call = await self._cache.get_full_chat(chat_id)
690
696
  if chat_call is not None:
691
- await self._app.send(
697
+ await self._invoke(
692
698
  EditGroupCallParticipant(
693
699
  call=chat_call,
694
700
  participant=participant,
@@ -727,5 +733,77 @@ class PyrogramClient(BridgedClient):
727
733
  def no_updates(self):
728
734
  return self._app.no_updates
729
735
 
736
+ async def _invoke(
737
+ self,
738
+ request,
739
+ dc_id: Optional[int] = None,
740
+ chat_id: Optional[int] = None,
741
+ sleep_threshold: Optional[int] = None,
742
+ ):
743
+ if chat_id is not None:
744
+ dc_id = self._cache.get_dc_call(chat_id)
745
+ if dc_id is None:
746
+ session = self._app
747
+ else:
748
+ session = self._app.media_sessions.get(dc_id)
749
+ if not session:
750
+ session = self._app.media_sessions[dc_id] = Session(
751
+ self._app,
752
+ dc_id,
753
+ await Auth(
754
+ self._app,
755
+ dc_id,
756
+ await self._app.storage.test_mode(),
757
+ ).create()
758
+ if dc_id != await self._app.storage.dc_id()
759
+ else await self._app.storage.auth_key(),
760
+ await self._app.storage.test_mode(),
761
+ is_media=True,
762
+ )
763
+ await session.start()
764
+ if dc_id != await self._app.storage.dc_id():
765
+ for _ in range(3):
766
+ exported_auth = await self._invoke(
767
+ ExportAuthorization(
768
+ dc_id=dc_id,
769
+ ),
770
+ )
771
+
772
+ try:
773
+ await session.invoke(
774
+ ImportAuthorization(
775
+ id=exported_auth.id,
776
+ bytes=exported_auth.bytes,
777
+ ),
778
+ )
779
+ except AuthBytesInvalid:
780
+ continue
781
+ else:
782
+ break
783
+ else:
784
+ raise AuthBytesInvalid
785
+ try:
786
+ return await session.invoke(
787
+ request,
788
+ sleep_threshold=sleep_threshold,
789
+ )
790
+ except (BadRequest, FileMigrate) as e:
791
+ dc_new = BridgedClient.extract_dc(
792
+ str(e),
793
+ )
794
+ if dc_new is not None:
795
+ if chat_id is not None:
796
+ self._cache.set_dc_call(
797
+ chat_id,
798
+ dc_new,
799
+ )
800
+ return await self._invoke(
801
+ request,
802
+ dc_new,
803
+ chat_id,
804
+ sleep_threshold,
805
+ )
806
+ raise
807
+
730
808
  async def start(self):
731
809
  await self._app.start()
@@ -6,7 +6,9 @@ from typing import Union
6
6
  from ntgcalls import MediaSegmentQuality
7
7
  from ntgcalls import Protocol
8
8
  from telethon import TelegramClient
9
+ from telethon.errors import BadRequestError
9
10
  from telethon.errors import ChannelPrivateError
11
+ from telethon.errors import FileMigrateError
10
12
  from telethon.errors import FloodWaitError
11
13
  from telethon.events import Raw
12
14
  from telethon.tl.functions.channels import GetFullChannelRequest
@@ -180,14 +182,17 @@ class TelethonClient(BridgedClient):
180
182
  ):
181
183
  participants = update.participants
182
184
  for participant in participants:
185
+ action = self.parse_participant_action(participant)
183
186
  result = self._cache.set_participants_cache_call(
184
187
  update.call.id,
188
+ action,
185
189
  self.parse_participant(participant),
186
190
  )
187
191
  if result is not None:
188
192
  await self._propagate(
189
193
  UpdatedGroupCallParticipant(
190
194
  self._cache.get_chat_id(update.call.id),
195
+ action,
191
196
  result,
192
197
  ),
193
198
  )
@@ -309,7 +314,7 @@ class TelethonClient(BridgedClient):
309
314
  chat = await self._app.get_input_entity(chat_id)
310
315
  if isinstance(chat, InputPeerChannel):
311
316
  input_call = (
312
- await self._app(
317
+ await self._invoke(
313
318
  GetFullChannelRequest(
314
319
  InputChannel(
315
320
  chat.channel_id,
@@ -320,14 +325,14 @@ class TelethonClient(BridgedClient):
320
325
  ).full_chat.call
321
326
  else:
322
327
  input_call = (
323
- await self._app(
328
+ await self._invoke(
324
329
  GetFullChatRequest(chat_id),
325
330
  )
326
331
  ).full_chat.call
327
332
 
328
333
  if input_call is not None:
329
334
  raw_call = (
330
- await self._app(
335
+ await self._invoke(
331
336
  GetGroupCallRequest(
332
337
  call=input_call,
333
338
  limit=-1,
@@ -340,6 +345,7 @@ class TelethonClient(BridgedClient):
340
345
  self._cache.set_participants_cache_chat(
341
346
  chat_id,
342
347
  call.id,
348
+ self.parse_participant_action(participant),
343
349
  self.parse_participant(participant),
344
350
  )
345
351
  if call.schedule_date is not None:
@@ -348,7 +354,7 @@ class TelethonClient(BridgedClient):
348
354
  return input_call
349
355
 
350
356
  async def get_dhc(self) -> DhConfig:
351
- return await self._app(
357
+ return await self._invoke(
352
358
  GetDhConfigRequest(
353
359
  version=0,
354
360
  random_length=256,
@@ -370,7 +376,7 @@ class TelethonClient(BridgedClient):
370
376
  participants = []
371
377
  next_offset = ''
372
378
  while True:
373
- result = await self._app(
379
+ result = await self._invoke(
374
380
  GetGroupParticipantsRequest(
375
381
  call=input_call,
376
382
  ids=[],
@@ -397,7 +403,7 @@ class TelethonClient(BridgedClient):
397
403
  ) -> str:
398
404
  chat_call = await self._cache.get_full_chat(chat_id)
399
405
  if chat_call is not None:
400
- result: Updates = await self._app(
406
+ result: Updates = await self._invoke(
401
407
  JoinGroupCallRequest(
402
408
  call=chat_call,
403
409
  params=DataJSON(data=json_join),
@@ -416,6 +422,7 @@ class TelethonClient(BridgedClient):
416
422
  for participant in participants:
417
423
  self._cache.set_participants_cache_call(
418
424
  update.call.id,
425
+ self.parse_participant_action(participant),
419
426
  self.parse_participant(participant),
420
427
  )
421
428
  if isinstance(update, UpdateGroupCallConnection):
@@ -430,7 +437,7 @@ class TelethonClient(BridgedClient):
430
437
  ):
431
438
  chat_call = await self._cache.get_full_chat(chat_id)
432
439
  if chat_call is not None:
433
- result: Updates = await self._app(
440
+ result: Updates = await self._invoke(
434
441
  JoinGroupCallPresentationRequest(
435
442
  call=chat_call,
436
443
  params=DataJSON(data=json_join),
@@ -448,7 +455,7 @@ class TelethonClient(BridgedClient):
448
455
  ):
449
456
  chat_call = await self._cache.get_full_chat(chat_id)
450
457
  if chat_call is not None:
451
- await self._app(
458
+ await self._invoke(
452
459
  LeaveGroupCallPresentationRequest(
453
460
  call=chat_call,
454
461
  ),
@@ -461,7 +468,7 @@ class TelethonClient(BridgedClient):
461
468
  protocol: Protocol,
462
469
  has_video: bool,
463
470
  ):
464
- update = await self._app(
471
+ update = await self._invoke(
465
472
  RequestCallRequest(
466
473
  user_id=await self.resolve_peer(user_id),
467
474
  random_id=self.rnd_id(),
@@ -484,7 +491,7 @@ class TelethonClient(BridgedClient):
484
491
  g_b: bytes,
485
492
  protocol: Protocol,
486
493
  ):
487
- return await self._app(
494
+ return await self._invoke(
488
495
  AcceptCallRequest(
489
496
  peer=self._cache.get_phone_call(user_id),
490
497
  g_b=g_b,
@@ -500,7 +507,7 @@ class TelethonClient(BridgedClient):
500
507
  protocol: Protocol,
501
508
  ) -> CallProtocol:
502
509
  res = (
503
- await self._app(
510
+ await self._invoke(
504
511
  ConfirmCallRequest(
505
512
  peer=self._cache.get_phone_call(user_id),
506
513
  g_a=g_a,
@@ -520,7 +527,7 @@ class TelethonClient(BridgedClient):
520
527
  user_id: int,
521
528
  data: bytes,
522
529
  ):
523
- await self._app(
530
+ await self._invoke(
524
531
  SendSignalingDataRequest(
525
532
  peer=self._cache.get_phone_call(user_id),
526
533
  data=data,
@@ -531,7 +538,7 @@ class TelethonClient(BridgedClient):
531
538
  self,
532
539
  chat_id: int,
533
540
  ):
534
- result: Updates = await self._app(
541
+ result: Updates = await self._invoke(
535
542
  CreateGroupCallRequest(
536
543
  peer=await self.resolve_peer(chat_id),
537
544
  random_id=self.rnd_id(),
@@ -561,7 +568,7 @@ class TelethonClient(BridgedClient):
561
568
  ):
562
569
  chat_call = await self._cache.get_full_chat(chat_id)
563
570
  if chat_call is not None:
564
- await self._app(
571
+ await self._invoke(
565
572
  LeaveGroupCallRequest(
566
573
  call=chat_call,
567
574
  source=0,
@@ -581,7 +588,7 @@ class TelethonClient(BridgedClient):
581
588
  if is_missed
582
589
  else PhoneCallDiscardReasonHangup()
583
590
  )
584
- await self._app(
591
+ await self._invoke(
585
592
  DiscardCallRequest(
586
593
  peer=peer,
587
594
  duration=0,
@@ -600,7 +607,7 @@ class TelethonClient(BridgedClient):
600
607
  ):
601
608
  chat_call = await self._cache.get_full_chat(chat_id)
602
609
  if chat_call is not None:
603
- await self._app(
610
+ await self._invoke(
604
611
  EditGroupCallParticipantRequest(
605
612
  call=chat_call,
606
613
  participant=participant,
@@ -621,7 +628,7 @@ class TelethonClient(BridgedClient):
621
628
  if chat_call is not None:
622
629
  try:
623
630
  return (
624
- await self._app(
631
+ await self._invoke(
625
632
  GetFileRequest(
626
633
  location=InputGroupCallStream(
627
634
  call=chat_call,
@@ -635,7 +642,8 @@ class TelethonClient(BridgedClient):
635
642
  offset=0,
636
643
  limit=limit,
637
644
  ),
638
- flood_sleep_threshold=0,
645
+ chat_id=chat_id,
646
+ sleep_threshold=0,
639
647
  )
640
648
  ).bytes
641
649
  except FloodWaitError:
@@ -648,12 +656,12 @@ class TelethonClient(BridgedClient):
648
656
  ):
649
657
  chat_call = await self._cache.get_full_chat(chat_id)
650
658
  if chat_call is not None:
651
- # noinspection PyBroadException
652
659
  channels = (
653
- await self._app(
660
+ await self._invoke(
654
661
  GetGroupCallStreamChannelsRequest(
655
662
  call=chat_call,
656
663
  ),
664
+ chat_id=chat_id,
657
665
  )
658
666
  ).channels
659
667
  if len(channels) > 0:
@@ -672,7 +680,7 @@ class TelethonClient(BridgedClient):
672
680
  ):
673
681
  chat_call = await self._cache.get_full_chat(chat_id)
674
682
  if chat_call is not None:
675
- await self._app(
683
+ await self._invoke(
676
684
  EditGroupCallParticipantRequest(
677
685
  call=chat_call,
678
686
  participant=participant,
@@ -711,6 +719,44 @@ class TelethonClient(BridgedClient):
711
719
  def no_updates(self):
712
720
  return False
713
721
 
722
+ # noinspection PyProtectedMember,PyUnresolvedReferences
723
+ async def _invoke(
724
+ self,
725
+ request,
726
+ dc_id: Optional[int] = None,
727
+ chat_id: Optional[int] = None,
728
+ sleep_threshold: Optional[int] = None,
729
+ ):
730
+ try:
731
+ if chat_id is not None:
732
+ dc_id = self._cache.get_dc_call(chat_id)
733
+ if dc_id is None or self._app.session.dc_id == dc_id:
734
+ sender_dc = self._app._sender
735
+ else:
736
+ sender_dc = await self._app._borrow_exported_sender(dc_id)
737
+ return await self._app._call(
738
+ sender_dc,
739
+ request,
740
+ flood_sleep_threshold=sleep_threshold,
741
+ )
742
+ except (BadRequestError, FileMigrateError) as e:
743
+ dc_new = BridgedClient.extract_dc(
744
+ str(e),
745
+ )
746
+ if dc_new is not None:
747
+ if chat_id is not None:
748
+ self._cache.set_dc_call(
749
+ chat_id,
750
+ dc_new,
751
+ )
752
+ return await self._invoke(
753
+ request,
754
+ dc_new,
755
+ chat_id,
756
+ sleep_threshold,
757
+ )
758
+ raise
759
+
714
760
  # noinspection PyUnresolvedReferences
715
761
  async def start(self):
716
762
  await self._app.start()
@@ -1,11 +1,11 @@
1
1
  from enum import auto
2
+ from enum import Flag
2
3
  from typing import List
3
4
  from typing import Optional
4
5
 
5
6
  from ntgcalls import SsrcGroup
6
7
 
7
8
  from ...types.py_object import PyObject
8
- from ..flag import Flag
9
9
 
10
10
 
11
11
  class GroupCallParticipant(PyObject):
@@ -33,8 +33,6 @@ class GroupCallParticipant(PyObject):
33
33
  video_camera: bool,
34
34
  raised_hand: bool,
35
35
  volume: int,
36
- joined: bool,
37
- left: bool,
38
36
  source: int,
39
37
  video_info: Optional[SourceInfo],
40
38
  presentation_info: Optional[SourceInfo],
@@ -48,12 +46,6 @@ class GroupCallParticipant(PyObject):
48
46
  self.video_camera: bool = video_camera
49
47
  self.raised_hand: bool = raised_hand
50
48
  self.volume: int = volume
51
- if joined:
52
- self.action = self.Action.JOINED
53
- elif left:
54
- self.action = self.Action.LEFT
55
- else:
56
- self.action = self.Action.UPDATED
57
49
  self.video_info: Optional[
58
50
  GroupCallParticipant.SourceInfo
59
51
  ] = video_info
@@ -6,7 +6,9 @@ class UpdatedGroupCallParticipant(Update):
6
6
  def __init__(
7
7
  self,
8
8
  chat_id: int,
9
+ action: GroupCallParticipant.Action,
9
10
  participant: GroupCallParticipant,
10
11
  ):
11
12
  super().__init__(chat_id)
13
+ self.action = action
12
14
  self.participant = participant
@@ -15,9 +15,10 @@ class ParticipantList:
15
15
 
16
16
  def update_participant(
17
17
  self,
18
+ action: GroupCallParticipant.Action,
18
19
  participant: GroupCallParticipant,
19
20
  ):
20
- if participant.action == GroupCallParticipant.Action.LEFT:
21
+ if action == GroupCallParticipant.Action.LEFT:
21
22
  if participant.user_id in self._list_participants:
22
23
  del self._list_participants[participant.user_id]
23
24
  else: