py-tgcalls 2.0.0rc2__py3-none-any.whl → 2.0.0rc4__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.1
2
2
  Name: py-tgcalls
3
- Version: 2.0.0rc2
3
+ Version: 2.0.0rc4
4
4
  Summary: UNKNOWN
5
5
  Home-page: https://github.com/pytgcalls/pytgcalls
6
6
  Author: Laky-64
@@ -22,7 +22,7 @@ Description-Content-Type: text/markdown
22
22
  License-File: LICENSE
23
23
  Requires-Dist: aiohttp (>=3.9.3)
24
24
  Requires-Dist: deprecation
25
- Requires-Dist: ntgcalls (>=1.1.3)
25
+ Requires-Dist: ntgcalls (>=1.2.0.b6)
26
26
  Requires-Dist: psutil
27
27
  Requires-Dist: screeninfo
28
28
  Requires-Dist: setuptools
@@ -1,14 +1,14 @@
1
1
  pytgcalls/__init__.py,sha256=TfZGf1enqqs50mBB406vygB6zYgn3vAjBYFUDO4Pviw,248
2
- pytgcalls/__version__.py,sha256=9mj-rh8xPacGvkhlbfmJuLzTPpmZa4UVQt74z5bJOR4,25
2
+ pytgcalls/__version__.py,sha256=TZk9uVn2m_Mjhob6LWvtgl022cEas816bZCaV4pwe-c,25
3
3
  pytgcalls/environment.py,sha256=ctCHACvG6l8SdpPewSBhOvc70kbwpv18maC0TwLvZ08,1924
4
- pytgcalls/exceptions.py,sha256=-h2WqnZeXbFIojcXSMsvYzsLOZiVZKzp4uZ00d-GTTA,3824
4
+ pytgcalls/exceptions.py,sha256=0MmAktc53ajYAc7ThjD2tJ9PDyibUi0iHZMfUy2IoKs,4109
5
5
  pytgcalls/ffmpeg.py,sha256=1GavkVf562Y_8cT4EZxxj_b7Y0-l8yyGkX0D5eUHeas,8520
6
6
  pytgcalls/filters.py,sha256=cmFWhRkgjQMk1WQqnd-hOAvM6x3dufJ1xjQAEL1vKLQ,4409
7
7
  pytgcalls/mtproto_required.py,sha256=6B-31p5qH_6oekUgypV4nK3hqPS6Nr-pA8S81wjnbaY,630
8
8
  pytgcalls/mutex.py,sha256=fSsAL4NuB7esBG90k4eUX388Knpr1_76Mz5BZlkSC0w,1119
9
- pytgcalls/pytgcalls.py,sha256=H8B5-16bn5xk5J7N4njJW-xIEMTPeYVxcBAomzn1gbs,1583
9
+ pytgcalls/pytgcalls.py,sha256=VI9aRwPE-Lo1lh18ByOnkFxf1_8tq2ECyz5igPo1r8w,1443
10
10
  pytgcalls/pytgcalls_session.py,sha256=_BGJWvf7t3mki2DhlEPjh9cypvYuSFkMSxzTsfepwUk,2719
11
- pytgcalls/scaffold.py,sha256=CSRLYfc4wGv0RE3JMPkmEV3JgFv5Ivh5REp1YkzPFfY,950
11
+ pytgcalls/scaffold.py,sha256=d5NFFm-Ntlu07fpXOE_OI4ULrvNb3Y4WDtM0nsKjqk4,986
12
12
  pytgcalls/statictypes.py,sha256=CdlqgQNhTZ_uTE8-B8m01fJ7TlD2B42EI2QBPxDdAtA,3842
13
13
  pytgcalls/sync.py,sha256=IsOH3TD7cxUg_-zdGt12HoS8sBlXvcGayPZAoxxKM48,3396
14
14
  pytgcalls/version_manager.py,sha256=egeGgvb66zWlLTMuw2U-b0x8MfnRzMm1xAEVN87HF5c,296
@@ -25,34 +25,34 @@ pytgcalls/methods/__init__.py,sha256=hk1blAT5u_Isemdrg0nqInLsdRzTTZnak5NdAfkBPAk
25
25
  pytgcalls/methods/calls/__init__.py,sha256=xg4DZZClEnxwaj-DAq3e8gSR-g-MiYBdUEBth64lSXA,214
26
26
  pytgcalls/methods/calls/change_volume_call.py,sha256=viA3yHVxPJ421yE1dfFTh-kNEFTxMlaVFxVjC-PeX-0,719
27
27
  pytgcalls/methods/calls/get_participants.py,sha256=dT725XXn9oiTbWV6mFradIydoQUx_COPButivDhzAxE,568
28
- pytgcalls/methods/calls/leave_call.py,sha256=VdJeift1afC3REU-yE3M85lToZeQieVlUj_SdPZJMi4,1101
28
+ pytgcalls/methods/calls/leave_call.py,sha256=ZjZbjlQn8KuX3mUjzXfX42EpL9_iU3fsXYdidfqUrUM,1091
29
29
  pytgcalls/methods/decorators/__init__.py,sha256=TCGaEVZnHjtOwv-3PNfaCVm0kyFhJApUPUNntt6MwyM,78
30
30
  pytgcalls/methods/decorators/on_update.py,sha256=ZTL4YcQk0N4Ru56a5WItUvkSN5SAqr6_RDZvXmZMIHs,316
31
31
  pytgcalls/methods/stream/__init__.py,sha256=_4j-CEby4_2Kadva86tFMC4GSSzhBBjKLXfrgTk4gzo,343
32
- pytgcalls/methods/stream/mute_stream.py,sha256=djw-CeH01kcviBVW9kMrMg_OYbtRjZhunDI953So9J4,580
33
- pytgcalls/methods/stream/pause_stream.py,sha256=QLGN_vtTC17YSgIlwcYhUCBWaaCZeFPIksQ9pId5V9A,583
34
- pytgcalls/methods/stream/play.py,sha256=UzwnbA-cPnWDomPkzOK5Lqk7iOV99WyMJD0LQBAFT_Q,7305
35
- pytgcalls/methods/stream/played_time.py,sha256=7L9nK8AQRQ-jEIIEOYgOcEksa86iql8K4ryh__e3KVk,580
36
- pytgcalls/methods/stream/resume_stream.py,sha256=IW5LPtkFcJiprm39FsJa1F_UssRmbD-kyx9LYwO4mI4,586
37
- pytgcalls/methods/stream/unmute_stream.py,sha256=H2ZmdG0p3BTqMpgLabM3U6S_r1K9DNvmJGs6Rjloel4,586
32
+ pytgcalls/methods/stream/mute_stream.py,sha256=auo2aAazfEC90Ab6MzaiPdddiJ1w4fN_9HaORkAeOBY,570
33
+ pytgcalls/methods/stream/pause_stream.py,sha256=z_AIWABrQMHmTwvlah_PrH9EjXbro8gKxZni4Km5ICg,573
34
+ pytgcalls/methods/stream/play.py,sha256=acuav8C9wEyur8FMAT7zFxkEvNDu45gnodUmGFrfIKA,7376
35
+ pytgcalls/methods/stream/played_time.py,sha256=IkUdyHrqpzpRl9uf0uZhg1COo4zsHnQOPu3nipjVatI,570
36
+ pytgcalls/methods/stream/resume_stream.py,sha256=z_DgP4cDExjEqEeX_ZL--50MXQ9lrATK876SIwE71PQ,576
37
+ pytgcalls/methods/stream/unmute_stream.py,sha256=KUMhfMbhsPmZsmpF4cGWC1FVW7YwXha2MmQnqrBhM8s,576
38
38
  pytgcalls/methods/utilities/__init__.py,sha256=JcKwqNo6fFXXfuab94fNEraKF1P9fnSSgr0WQDRjF2w,339
39
39
  pytgcalls/methods/utilities/cache_peer.py,sha256=Ylt0wCCJOoNKf1wZEXjfE8aBZKUIIgdRUFOMTGA5DfE,140
40
- pytgcalls/methods/utilities/call_holder.py,sha256=Ateys37G06hliEyyIGYfP08e9AH6P1R5NNxKjuPqrQk,903
40
+ pytgcalls/methods/utilities/call_holder.py,sha256=RZ9DFhZO66ghtGqxLbYS86hq2UCjTzTiN_xzL5bgD-M,903
41
41
  pytgcalls/methods/utilities/compose.py,sha256=Nzdv8orMmka5NIBZ1SW1nsqXRzArZl4m6FdZU7syaR4,334
42
42
  pytgcalls/methods/utilities/cpu_usage.py,sha256=Mbga4MFCIwuh7WC8sqBbv1Pa6ALcp5AIDyfYMH_Bix4,162
43
43
  pytgcalls/methods/utilities/idle.py,sha256=lkjbYzpU7iz-maE0kS6RVtHJ4h1PsmGqnZmaENGIKeE,768
44
44
  pytgcalls/methods/utilities/ping.py,sha256=hhIMSHk2BzMB-IKpwLdZFVrsEvGm2ftJwKLs1k4anh8,244
45
45
  pytgcalls/methods/utilities/resolve_chat_id.py,sha256=92x2LHbUlnJMm-kS3fXOYmzYpY2TZbqtQD2rw3eBXDY,382
46
46
  pytgcalls/methods/utilities/run.py,sha256=cnYQd2xB5Cr_WS0Q2cXJZPGiN6JOCULzj1r4xXVyrlg,152
47
- pytgcalls/methods/utilities/start.py,sha256=99ey8496uzFdntiPg4wbveRebY05dYIglXpSnrl5Pec,6702
47
+ pytgcalls/methods/utilities/start.py,sha256=0TjW64IDYulevNTJIp4ZHWa9pkKCcgeyFhL47PehoqI,8534
48
48
  pytgcalls/methods/utilities/stream_params.py,sha256=hYcNxx__McmPeHgOUDEuNcN7ThgDjukejQYHrfmWm-A,1519
49
49
  pytgcalls/mtproto/__init__.py,sha256=X4zvzFG7km7qHyE0fdvA550WcOVO_xl_p__gvIfDGmw,130
50
- pytgcalls/mtproto/bridged_client.py,sha256=LBY1bsyOVyUqNT8RtxPj-Lbq-SGvbJ4L28AFgO_Claw,5039
50
+ pytgcalls/mtproto/bridged_client.py,sha256=kK22n-CKjtfmtNE6bXCpuL6kWAUK2_Ul7cGgx_HNuHQ,4975
51
51
  pytgcalls/mtproto/client_cache.py,sha256=LYjmvhgaaEyczoJFZ35vGXFlN4ADwXYvt1bhrVS4ipw,5088
52
- pytgcalls/mtproto/hydrogram_client.py,sha256=SIYdKPw_1Epp1BLExIF4fDh3VCbUcpEAJGVf_GWfyoQ,20904
53
- pytgcalls/mtproto/mtproto_client.py,sha256=Bk5N2OtKR-zvwHotGtTs6kmr9a2JX0bWxocxYTxgTDo,6928
54
- pytgcalls/mtproto/pyrogram_client.py,sha256=IpPteY4b-dHBJ-T-FNo2VEkAwnVXiyMznCXsBlof6u4,21182
55
- pytgcalls/mtproto/telethon_client.py,sha256=mg-2LapOHXWPAp5614LjxnY2T-SOOtOd75J3iWEIOwQ,19997
52
+ pytgcalls/mtproto/hydrogram_client.py,sha256=TgItS6KKPJna1yIXJ7iXflfRWRpPvMXHoRKzo6q09lE,21014
53
+ pytgcalls/mtproto/mtproto_client.py,sha256=rqsUOE7llTXSAru9GfBMhUKufEgWQL65QLHRj4TEfgw,6884
54
+ pytgcalls/mtproto/pyrogram_client.py,sha256=cNaQu00rZTFVTj3CE2V_eL5yT1XcGwkgwcGfb6aa53s,21203
55
+ pytgcalls/mtproto/telethon_client.py,sha256=GFZ0LM8PXRVXwJfYV_gVVZ_qjEmWCJD_nmqiPE8oCCo,20105
56
56
  pytgcalls/types/__init__.py,sha256=JTMTa2flwWkBSEjhAAXE0oL4IJFRb12XU0npp9Neypc,1071
57
57
  pytgcalls/types/browsers.py,sha256=47Kr5q96n4Q4WvVhA6IUlS2egEcA9GRLlDeFcQYyc9M,9545
58
58
  pytgcalls/types/cache.py,sha256=FfsOcmYnsBGPlJoTPIXXYcUSpGE3rhx6cjIH77hyUL0,1059
@@ -82,12 +82,12 @@ pytgcalls/types/raw/video_parameters.py,sha256=LXBpdaw5vyNayVfgtmF-gRkCY_ATwAnun
82
82
  pytgcalls/types/raw/video_stream.py,sha256=2Chrk7NFWF1H9V7hH71RZ5rF3iBhT53syFkHKw4-5gc,433
83
83
  pytgcalls/types/stream/__init__.py,sha256=xfF-9ZulOLk3E6G1nw1Ky0ZRWXlFuER0Uj8HQn3650w,338
84
84
  pytgcalls/types/stream/audio_quality.py,sha256=4X94ErmTeLP4TVcE3eLtPPdtluSPxgxbgTosuNJOVhc,141
85
- pytgcalls/types/stream/media_stream.py,sha256=68ji9bDw6edXFcnB5391kdsJrLTDUdjRPNlG0pZBiHA,8978
85
+ pytgcalls/types/stream/media_stream.py,sha256=vH32FrwdMSA9-S54bvessVHewh_l-5WXqupQE8pe-x4,8979
86
86
  pytgcalls/types/stream/stream_audio_ended.py,sha256=2_EFa98F0vWu0d0jBmLtzp4NH_xBkDO_6yP9UtyKuCs,164
87
87
  pytgcalls/types/stream/stream_video_ended.py,sha256=9YFTTZPMDpB95eb815rGtgDrzBGfTeazJ5mZwP6Hvks,164
88
88
  pytgcalls/types/stream/video_quality.py,sha256=HBfWq005kh-D19MaVE9VzVdnODzrXf4IJUimCfslfiU,231
89
- py_tgcalls-2.0.0rc2.dist-info/LICENSE,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
90
- py_tgcalls-2.0.0rc2.dist-info/METADATA,sha256=knBJQ-o80woqWPY4hnlesmREiP9Vvq3y5KRKfM8jXa0,4883
91
- py_tgcalls-2.0.0rc2.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
92
- py_tgcalls-2.0.0rc2.dist-info/top_level.txt,sha256=IUDUwn0KkcbUYZbCe9R5AUb2Ob-lmllNUGQqyeXXd8A,10
93
- py_tgcalls-2.0.0rc2.dist-info/RECORD,,
89
+ py_tgcalls-2.0.0rc4.dist-info/LICENSE,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
90
+ py_tgcalls-2.0.0rc4.dist-info/METADATA,sha256=WRIeNUG7mRIALS23Oi0h_2bzY5o0eLfzuQAZpjaATtg,4886
91
+ py_tgcalls-2.0.0rc4.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
92
+ py_tgcalls-2.0.0rc4.dist-info/top_level.txt,sha256=IUDUwn0KkcbUYZbCe9R5AUb2Ob-lmllNUGQqyeXXd8A,10
93
+ py_tgcalls-2.0.0rc4.dist-info/RECORD,,
pytgcalls/__version__.py CHANGED
@@ -1 +1 @@
1
- __version__ = '2.0.0rc2'
1
+ __version__ = '2.0.0rc4'
pytgcalls/exceptions.py CHANGED
@@ -65,10 +65,24 @@ class TimedOutAnswer(Exception):
65
65
  )
66
66
 
67
67
 
68
- class NotInGroupCallError(Exception):
68
+ class CallDeclined(Exception):
69
+ def __init__(self, user_id: int):
70
+ super().__init__(
71
+ f'Call declined by {user_id}',
72
+ )
73
+
74
+
75
+ class CallDiscarded(Exception):
76
+ def __init__(self, user_id: int):
77
+ super().__init__(
78
+ f'Call discarded by {user_id}',
79
+ )
80
+
81
+
82
+ class NotInCallError(Exception):
69
83
  def __init__(self):
70
84
  super().__init__(
71
- 'The userbot there isn\'t in a group call',
85
+ 'The userbot is not in a call',
72
86
  )
73
87
 
74
88
 
@@ -3,7 +3,7 @@ from typing import Union
3
3
  from ntgcalls import ConnectionNotFound
4
4
 
5
5
  from ...exceptions import NoActiveGroupCall
6
- from ...exceptions import NotInGroupCallError
6
+ from ...exceptions import NotInCallError
7
7
  from ...mtproto_required import mtproto_required
8
8
  from ...mutex import mutex
9
9
  from ...scaffold import Scaffold
@@ -35,6 +35,6 @@ class LeaveCall(Scaffold):
35
35
  try:
36
36
  await self._binding.stop(chat_id)
37
37
  except ConnectionNotFound:
38
- raise NotInGroupCallError()
38
+ raise NotInCallError()
39
39
  if chat_id < 0: # type: ignore
40
40
  self._need_unmute.discard(chat_id)
@@ -2,7 +2,7 @@ from typing import Union
2
2
 
3
3
  from ntgcalls import ConnectionNotFound
4
4
 
5
- from ...exceptions import NotInGroupCallError
5
+ from ...exceptions import NotInCallError
6
6
  from ...mtproto_required import mtproto_required
7
7
  from ...scaffold import Scaffold
8
8
  from ...statictypes import statictypes
@@ -19,4 +19,4 @@ class MuteStream(Scaffold):
19
19
  try:
20
20
  return await self._binding.mute(chat_id)
21
21
  except ConnectionNotFound:
22
- raise NotInGroupCallError()
22
+ raise NotInCallError()
@@ -2,7 +2,7 @@ from typing import Union
2
2
 
3
3
  from ntgcalls import ConnectionNotFound
4
4
 
5
- from ...exceptions import NotInGroupCallError
5
+ from ...exceptions import NotInCallError
6
6
  from ...mtproto_required import mtproto_required
7
7
  from ...scaffold import Scaffold
8
8
  from ...statictypes import statictypes
@@ -19,4 +19,4 @@ class PauseStream(Scaffold):
19
19
  try:
20
20
  return await self._binding.pause(chat_id)
21
21
  except ConnectionNotFound:
22
- raise NotInGroupCallError()
22
+ raise NotInCallError()
@@ -37,13 +37,10 @@ class Play(Scaffold):
37
37
  config: Optional[Union[CallConfig, GroupCallConfig]] = None,
38
38
  ):
39
39
  chat_id = await self.resolve_chat_id(chat_id)
40
+ is_p2p = chat_id > 0 # type: ignore
40
41
  if config is None:
41
- config = GroupCallConfig() \
42
- if chat_id < 0 else CallConfig() # type: ignore
43
- if (
44
- chat_id < 0 and # type: ignore
45
- not isinstance(config, GroupCallConfig)
46
- ):
42
+ config = GroupCallConfig() if not is_p2p else CallConfig()
43
+ if not is_p2p and not isinstance(config, GroupCallConfig):
47
44
  raise ValueError(
48
45
  'Group call config must be provided for group calls',
49
46
  )
@@ -81,6 +78,7 @@ class Play(Scaffold):
81
78
  try:
82
79
  for retries in range(4):
83
80
  try:
81
+ self._wait_connect[chat_id] = self.loop.create_future()
84
82
  if isinstance(config, GroupCallConfig):
85
83
  call_params: str = await self._binding.create_call(
86
84
  chat_id,
@@ -121,7 +119,6 @@ class Play(Scaffold):
121
119
  chat_id,
122
120
  data.g_a_or_b,
123
121
  self._binding.get_protocol(),
124
- media_description.video is not None,
125
122
  )
126
123
 
127
124
  try:
@@ -131,7 +128,6 @@ class Play(Scaffold):
131
128
  )
132
129
  auth_params = await self._binding.exchange_keys(
133
130
  chat_id,
134
- data.p,
135
131
  result.g_a_or_b,
136
132
  result.fingerprint,
137
133
  )
@@ -153,9 +149,10 @@ class Play(Scaffold):
153
149
  raise TimedOutAnswer()
154
150
  finally:
155
151
  self._p2p_configs.pop(chat_id, None)
152
+ await self._wait_connect[chat_id]
156
153
  break
157
154
  except TelegramServerError:
158
- if retries == 3:
155
+ if retries == 3 or is_p2p:
159
156
  raise
160
157
  (py_logger.warning if retries >= 1 else py_logger.info)(
161
158
  f'Telegram is having some internal server issues. '
@@ -167,6 +164,8 @@ class Play(Scaffold):
167
164
  except ConnectionNotFound:
168
165
  pass
169
166
  raise
167
+ finally:
168
+ self._wait_connect.pop(chat_id, None)
170
169
 
171
170
  if isinstance(config, GroupCallConfig):
172
171
  participants = await self._app.get_group_call_participants(
@@ -2,7 +2,7 @@ from typing import Union
2
2
 
3
3
  from ntgcalls import ConnectionNotFound
4
4
 
5
- from ...exceptions import NotInGroupCallError
5
+ from ...exceptions import NotInCallError
6
6
  from ...mtproto_required import mtproto_required
7
7
  from ...scaffold import Scaffold
8
8
  from ...statictypes import statictypes
@@ -19,4 +19,4 @@ class PlayedTime(Scaffold):
19
19
  try:
20
20
  return await self._binding.time(chat_id)
21
21
  except ConnectionNotFound:
22
- raise NotInGroupCallError()
22
+ raise NotInCallError()
@@ -2,7 +2,7 @@ from typing import Union
2
2
 
3
3
  from ntgcalls import ConnectionNotFound
4
4
 
5
- from ...exceptions import NotInGroupCallError
5
+ from ...exceptions import NotInCallError
6
6
  from ...mtproto_required import mtproto_required
7
7
  from ...scaffold import Scaffold
8
8
  from ...statictypes import statictypes
@@ -19,4 +19,4 @@ class ResumeStream(Scaffold):
19
19
  try:
20
20
  return await self._binding.resume(chat_id)
21
21
  except ConnectionNotFound:
22
- raise NotInGroupCallError()
22
+ raise NotInCallError()
@@ -2,7 +2,7 @@ from typing import Union
2
2
 
3
3
  from ntgcalls import ConnectionNotFound
4
4
 
5
- from ...exceptions import NotInGroupCallError
5
+ from ...exceptions import NotInCallError
6
6
  from ...mtproto_required import mtproto_required
7
7
  from ...scaffold import Scaffold
8
8
  from ...statictypes import statictypes
@@ -19,4 +19,4 @@ class UnMuteStream(Scaffold):
19
19
  try:
20
20
  return await self._binding.unmute(chat_id)
21
21
  except ConnectionNotFound:
22
- raise NotInGroupCallError()
22
+ raise NotInCallError()
@@ -9,9 +9,9 @@ class CallHolder(Scaffold):
9
9
  def __init__(self):
10
10
  super().__init__()
11
11
  self._conversions = {
12
- StreamStatus.Playing: Call.Status.PLAYING,
13
- StreamStatus.Paused: Call.Status.PAUSED,
14
- StreamStatus.Idling: Call.Status.IDLE,
12
+ StreamStatus.PLAYING: Call.Status.PLAYING,
13
+ StreamStatus.PAUSED: Call.Status.PAUSED,
14
+ StreamStatus.IDLING: Call.Status.IDLE,
15
15
  }
16
16
 
17
17
  @property
@@ -2,9 +2,13 @@ import asyncio
2
2
  import logging
3
3
 
4
4
  from ntgcalls import ConnectionNotFound
5
+ from ntgcalls import ConnectionState
5
6
  from ntgcalls import MediaState
6
7
  from ntgcalls import StreamType
8
+ from ntgcalls import TelegramServerError
7
9
 
10
+ from ...exceptions import CallDeclined
11
+ from ...exceptions import CallDiscarded
8
12
  from ...exceptions import PyTgCallsAlreadyRunning
9
13
  from ...mtproto import BridgedClient
10
14
  from ...pytgcalls_session import PyTgCallsSession
@@ -26,13 +30,29 @@ class Start(Scaffold):
26
30
  @self._app.on_update()
27
31
  async def update_handler(update: Update):
28
32
  chat_id = update.chat_id
29
- if isinstance(update, RawCallUpdate):
30
- if update.chat_id in self._p2p_configs:
31
- if update.status & RawCallUpdate.Type.UPDATED_CALL:
32
- if not self._p2p_configs[chat_id].wait_data.done():
33
+ if update.chat_id in self._p2p_configs:
34
+ if not self._p2p_configs[chat_id].wait_data.done():
35
+ if isinstance(update, RawCallUpdate):
36
+ if update.status & RawCallUpdate.Type.UPDATED_CALL:
33
37
  self._p2p_configs[chat_id].wait_data.set_result(
34
38
  update,
35
39
  )
40
+ if isinstance(update, ChatUpdate):
41
+ if update.status & ChatUpdate.Status.DISCARDED_CALL:
42
+ self._p2p_configs[chat_id].wait_data.set_exception(
43
+ CallDeclined(
44
+ chat_id,
45
+ ),
46
+ )
47
+ if chat_id in self._wait_connect and \
48
+ not self._wait_connect[chat_id].done():
49
+ if isinstance(update, ChatUpdate):
50
+ if update.status & ChatUpdate.Status.DISCARDED_CALL:
51
+ self._wait_connect[chat_id].set_exception(
52
+ CallDiscarded(
53
+ chat_id,
54
+ ),
55
+ )
36
56
  if isinstance(update, RawCallUpdate):
37
57
  if update.status & RawCallUpdate.Type.REQUESTED:
38
58
  self._p2p_configs[chat_id] = CallData(
@@ -86,7 +106,6 @@ class Start(Scaffold):
86
106
  )
87
107
 
88
108
  async def clear_call(chat_id):
89
- self._p2p_configs.pop(chat_id, None)
90
109
  try:
91
110
  await self._binding.stop(chat_id)
92
111
  except ConnectionNotFound:
@@ -109,7 +128,7 @@ class Start(Scaffold):
109
128
  await self.propagate(
110
129
  StreamAudioEnded(
111
130
  chat_id,
112
- ) if stream == stream.Audio else
131
+ ) if stream == StreamType.AUDIO else
113
132
  StreamVideoEnded(
114
133
  chat_id,
115
134
  ),
@@ -123,7 +142,26 @@ class Start(Scaffold):
123
142
  data,
124
143
  )
125
144
 
145
+ async def connection_changed(chat_id: int, state: ConnectionState):
146
+ if chat_id in self._wait_connect:
147
+ if state == ConnectionState.CONNECTED:
148
+ self._wait_connect[chat_id].set_result(None)
149
+ elif state == ConnectionState.FAILED or\
150
+ state == ConnectionState.TIMEOUT:
151
+ self._wait_connect[chat_id].set_exception(
152
+ TelegramServerError(),
153
+ )
154
+ await clear_call(chat_id)
155
+
156
+ if state == ConnectionState.FAILED or \
157
+ state == ConnectionState.TIMEOUT or \
158
+ state == ConnectionState.CLOSED:
159
+ if chat_id > 0:
160
+ await self._app.discard_call(chat_id)
161
+ await clear_call(chat_id)
162
+
126
163
  async def clear_cache(chat_id: int):
164
+ self._p2p_configs.pop(chat_id, None)
127
165
  self._cache_user_peer.pop(chat_id)
128
166
  self._need_unmute.discard(chat_id)
129
167
 
@@ -159,9 +197,9 @@ class Start(Scaffold):
159
197
  self.loop,
160
198
  ),
161
199
  )
162
- self._binding.on_disconnect(
163
- lambda chat_id: asyncio.run_coroutine_threadsafe(
164
- clear_cache(chat_id),
200
+ self._binding.on_connection_change(
201
+ lambda chat_id, state: asyncio.run_coroutine_threadsafe(
202
+ connection_changed(chat_id, state),
165
203
  self.loop,
166
204
  ),
167
205
  )
@@ -34,7 +34,6 @@ class BridgedClient(HandlersHolder):
34
34
  user_id: int,
35
35
  g_a_hash: bytes,
36
36
  protocol: Protocol,
37
- video: bool,
38
37
  ):
39
38
  pass
40
39
 
@@ -151,15 +150,10 @@ class BridgedClient(HandlersHolder):
151
150
  class_name = input_peer.__class__.__name__
152
151
  if class_name in ['PeerUser', 'InputPeerUser']:
153
152
  return input_peer.user_id
154
- elif (
155
- hasattr(input_peer, 'channel_id') or
156
- class_name in ['Channel', 'ChannelForbidden']
157
- ):
158
- return -1000000000000 - getattr(
159
- input_peer,
160
- 'channel_id',
161
- input_peer.id,
162
- )
153
+ elif class_name in ['Channel', 'ChannelForbidden']:
154
+ return -1000000000000 - input_peer.id
155
+ elif hasattr(input_peer, 'channel_id'):
156
+ return -1000000000000 - input_peer.channel_id
163
157
  elif class_name == 'Chat':
164
158
  return -input_peer.id
165
159
  else:
@@ -168,7 +162,7 @@ class BridgedClient(HandlersHolder):
168
162
  @staticmethod
169
163
  def user_from_call(call) -> Optional[int]:
170
164
  class_name = call.__class__.__name__
171
- if class_name == 'PhoneCallAccepted':
165
+ if class_name in ['PhoneCallAccepted', 'PhoneCallWaiting']:
172
166
  return call.participant_id
173
167
  elif class_name in ['PhoneCallRequested', 'PhoneCall']:
174
168
  return call.admin_id
@@ -43,6 +43,7 @@ from hydrogram.raw.types import PhoneCallDiscarded
43
43
  from hydrogram.raw.types import PhoneCallDiscardReasonHangup
44
44
  from hydrogram.raw.types import PhoneCallProtocol
45
45
  from hydrogram.raw.types import PhoneCallRequested
46
+ from hydrogram.raw.types import PhoneCallWaiting
46
47
  from hydrogram.raw.types import UpdateChannel
47
48
  from hydrogram.raw.types import UpdateGroupCall
48
49
  from hydrogram.raw.types import UpdateGroupCallConnection
@@ -97,7 +98,7 @@ class HydrogramClient(BridgedClient):
97
98
  ):
98
99
  if isinstance(
99
100
  update.phone_call,
100
- (PhoneCallAccepted, PhoneCallRequested),
101
+ (PhoneCallAccepted, PhoneCallRequested, PhoneCallWaiting),
101
102
  ):
102
103
  self._cache.set_phone_call(
103
104
  self.user_from_call(update.phone_call),
@@ -406,7 +407,6 @@ class HydrogramClient(BridgedClient):
406
407
  user_id: int,
407
408
  g_a_hash: bytes,
408
409
  protocol: Protocol,
409
- video: bool,
410
410
  ):
411
411
  await self._app.invoke(
412
412
  RequestCall(
@@ -414,7 +414,7 @@ class HydrogramClient(BridgedClient):
414
414
  random_id=self.rnd_id(),
415
415
  g_a_hash=g_a_hash,
416
416
  protocol=self.parse_protocol(protocol),
417
- video=video,
417
+ video=False,
418
418
  ),
419
419
  )
420
420
 
@@ -512,9 +512,12 @@ class HydrogramClient(BridgedClient):
512
512
  self,
513
513
  chat_id: int,
514
514
  ):
515
+ peer = self._cache.get_phone_call(chat_id)
516
+ if peer is None:
517
+ return
515
518
  await self._app.invoke(
516
519
  DiscardCall(
517
- peer=self._cache.get_phone_call(chat_id),
520
+ peer=peer,
518
521
  duration=0,
519
522
  reason=PhoneCallDiscardReasonHangup(),
520
523
  connection_id=0,
@@ -74,14 +74,12 @@ class MtProtoClient:
74
74
  user_id: int,
75
75
  g_a_hash: bytes,
76
76
  protocol: Protocol,
77
- video: bool,
78
77
  ):
79
78
  if self._bind_client is not None:
80
79
  return await self._bind_client.request_call(
81
80
  user_id,
82
81
  g_a_hash,
83
82
  protocol,
84
- video,
85
83
  )
86
84
  else:
87
85
  raise InvalidMTProtoClient()
@@ -45,6 +45,7 @@ from pyrogram.raw.types import PhoneCallDiscarded
45
45
  from pyrogram.raw.types import PhoneCallDiscardReasonHangup
46
46
  from pyrogram.raw.types import PhoneCallProtocol
47
47
  from pyrogram.raw.types import PhoneCallRequested
48
+ from pyrogram.raw.types import PhoneCallWaiting
48
49
  from pyrogram.raw.types import UpdateChannel
49
50
  from pyrogram.raw.types import UpdateGroupCall
50
51
  from pyrogram.raw.types import UpdateGroupCallConnection
@@ -105,7 +106,7 @@ class PyrogramClient(BridgedClient):
105
106
  ):
106
107
  if isinstance(
107
108
  update.phone_call,
108
- (PhoneCallAccepted, PhoneCallRequested),
109
+ (PhoneCallAccepted, PhoneCallRequested, PhoneCallWaiting),
109
110
  ):
110
111
  self._cache.set_phone_call(
111
112
  self.user_from_call(update.phone_call),
@@ -301,8 +302,8 @@ class PyrogramClient(BridgedClient):
301
302
  raise ContinuePropagation()
302
303
 
303
304
  async def get_call(
304
- self,
305
- chat_id: int,
305
+ self,
306
+ chat_id: int,
306
307
  ) -> Optional[InputGroupCall]:
307
308
  chat = await self._app.resolve_peer(chat_id)
308
309
  if isinstance(chat, InputPeerChannel):
@@ -347,16 +348,16 @@ class PyrogramClient(BridgedClient):
347
348
  )
348
349
 
349
350
  async def get_group_call_participants(
350
- self,
351
- chat_id: int,
351
+ self,
352
+ chat_id: int,
352
353
  ):
353
354
  return await self._cache.get_participant_list(
354
355
  chat_id,
355
356
  )
356
357
 
357
358
  async def get_participants(
358
- self,
359
- input_call: InputGroupCall,
359
+ self,
360
+ input_call: InputGroupCall,
360
361
  ) -> List[GroupCallParticipant]:
361
362
  return [
362
363
  self.parse_participant(participant)
@@ -374,12 +375,12 @@ class PyrogramClient(BridgedClient):
374
375
  ]
375
376
 
376
377
  async def join_group_call(
377
- self,
378
- chat_id: int,
379
- json_join: str,
380
- invite_hash: str,
381
- have_video: bool,
382
- join_as: InputPeer,
378
+ self,
379
+ chat_id: int,
380
+ json_join: str,
381
+ invite_hash: str,
382
+ have_video: bool,
383
+ join_as: InputPeer,
383
384
  ) -> str:
384
385
  chat_call = await self._cache.get_full_chat(chat_id)
385
386
  if chat_call is not None:
@@ -414,7 +415,6 @@ class PyrogramClient(BridgedClient):
414
415
  user_id: int,
415
416
  g_a_hash: bytes,
416
417
  protocol: Protocol,
417
- video: bool,
418
418
  ):
419
419
  await self._app.invoke(
420
420
  RequestCall(
@@ -422,7 +422,7 @@ class PyrogramClient(BridgedClient):
422
422
  random_id=self.rnd_id(),
423
423
  g_a_hash=g_a_hash,
424
424
  protocol=self.parse_protocol(protocol),
425
- video=video,
425
+ video=False,
426
426
  ),
427
427
  )
428
428
 
@@ -520,9 +520,12 @@ class PyrogramClient(BridgedClient):
520
520
  self,
521
521
  chat_id: int,
522
522
  ):
523
+ peer = self._cache.get_phone_call(chat_id)
524
+ if peer is None:
525
+ return
523
526
  await self._app.invoke(
524
527
  DiscardCall(
525
- peer=self._cache.get_phone_call(chat_id),
528
+ peer=peer,
526
529
  duration=0,
527
530
  reason=PhoneCallDiscardReasonHangup(),
528
531
  connection_id=0,
@@ -532,10 +535,10 @@ class PyrogramClient(BridgedClient):
532
535
  self._cache.drop_phone_call(chat_id)
533
536
 
534
537
  async def change_volume(
535
- self,
536
- chat_id: int,
537
- volume: int,
538
- participant: InputPeer,
538
+ self,
539
+ chat_id: int,
540
+ volume: int,
541
+ participant: InputPeer,
539
542
  ):
540
543
  chat_call = await self._cache.get_full_chat(chat_id)
541
544
  if chat_call is not None:
@@ -549,12 +552,12 @@ class PyrogramClient(BridgedClient):
549
552
  )
550
553
 
551
554
  async def set_call_status(
552
- self,
553
- chat_id: int,
554
- muted_status: Optional[bool],
555
- paused_status: Optional[bool],
556
- stopped_status: Optional[bool],
557
- participant: InputPeer,
555
+ self,
556
+ chat_id: int,
557
+ muted_status: Optional[bool],
558
+ paused_status: Optional[bool],
559
+ stopped_status: Optional[bool],
560
+ participant: InputPeer,
558
561
  ):
559
562
  chat_call = await self._cache.get_full_chat(chat_id)
560
563
  if chat_call is not None:
@@ -39,6 +39,7 @@ from telethon.tl.types import PhoneCallDiscarded
39
39
  from telethon.tl.types import PhoneCallDiscardReasonHangup
40
40
  from telethon.tl.types import PhoneCallProtocol
41
41
  from telethon.tl.types import PhoneCallRequested
42
+ from telethon.tl.types import PhoneCallWaiting
42
43
  from telethon.tl.types import TypeInputChannel
43
44
  from telethon.tl.types import TypeInputPeer
44
45
  from telethon.tl.types import TypeInputUser
@@ -95,7 +96,7 @@ class TelethonClient(BridgedClient):
95
96
  ):
96
97
  if isinstance(
97
98
  update.phone_call,
98
- (PhoneCallAccepted, PhoneCallRequested),
99
+ (PhoneCallAccepted, PhoneCallRequested, PhoneCallWaiting),
99
100
  ):
100
101
  self._cache.set_phone_call(
101
102
  self.user_from_call(update.phone_call),
@@ -383,7 +384,6 @@ class TelethonClient(BridgedClient):
383
384
  user_id: int,
384
385
  g_a_hash: bytes,
385
386
  protocol: Protocol,
386
- video: bool,
387
387
  ):
388
388
  return await self._app(
389
389
  RequestCallRequest(
@@ -391,7 +391,7 @@ class TelethonClient(BridgedClient):
391
391
  random_id=self.rnd_id(),
392
392
  g_a_hash=g_a_hash,
393
393
  protocol=self.parse_protocol(protocol),
394
- video=video,
394
+ video=False,
395
395
  ),
396
396
  )
397
397
 
@@ -489,9 +489,12 @@ class TelethonClient(BridgedClient):
489
489
  self,
490
490
  chat_id: int,
491
491
  ):
492
+ peer = self._cache.get_phone_call(chat_id)
493
+ if peer is None:
494
+ return
492
495
  await self._app(
493
496
  DiscardCallRequest(
494
- peer=self._cache.get_phone_call(chat_id),
497
+ peer=peer,
495
498
  duration=0,
496
499
  reason=PhoneCallDiscardReasonHangup(),
497
500
  connection_id=0,
pytgcalls/pytgcalls.py CHANGED
@@ -2,7 +2,6 @@ import asyncio
2
2
  import os
3
3
  from concurrent.futures import ThreadPoolExecutor
4
4
  from typing import Any
5
- from typing import Optional
6
5
 
7
6
  from ntgcalls import NTgCalls
8
7
 
@@ -24,8 +23,6 @@ class PyTgCalls(Methods, Scaffold):
24
23
  app: Any,
25
24
  workers: int = WORKERS,
26
25
  cache_duration: int = CACHE_DURATION,
27
- ntg_logs_path: Optional[str] = None,
28
- allow_rtc_logs: bool = False,
29
26
  ):
30
27
  super().__init__()
31
28
  self._mtproto = app
@@ -41,7 +38,7 @@ class PyTgCalls(Methods, Scaffold):
41
38
  self._app.package_name,
42
39
  )
43
40
  self._cache_user_peer = Cache()
44
- self._binding = NTgCalls(ntg_logs_path, allow_rtc_logs)
41
+ self._binding = NTgCalls()
45
42
  self.loop = asyncio.get_event_loop()
46
43
  self.workers = workers
47
44
  self.executor = ThreadPoolExecutor(
pytgcalls/scaffold.py CHANGED
@@ -23,6 +23,7 @@ class Scaffold(HandlersHolder):
23
23
  self._need_unmute = set()
24
24
  self._lock = dict()
25
25
  self._p2p_configs = dict()
26
+ self._wait_connect = dict()
26
27
 
27
28
  def _handle_mtproto(self):
28
29
  pass
@@ -240,7 +240,7 @@ class MediaStream(Stream):
240
240
 
241
241
  @staticmethod
242
242
  def _flags(flags: Flags) -> InputMode:
243
- new_flags = InputMode.Shell
243
+ new_flags = InputMode.SHELL
244
244
  if flags & MediaStream.Flags.NO_LATENCY:
245
- new_flags |= InputMode.NoLatency
245
+ new_flags |= InputMode.NO_LATENCY
246
246
  return new_flags