py-tgcalls 2.0.1__py3-none-any.whl → 2.0.3__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.1
3
+ Version: 2.0.3
4
4
  Summary: Async client API for the Telegram Calls.
5
5
  Author-email: Laky-64 <iraci.matteo@gmail.com>
6
6
  License: GNU LESSER GENERAL PUBLIC LICENSE
@@ -186,17 +186,17 @@ Classifier: Programming Language :: Python :: 3.12
186
186
  Requires-Python: >=3.8
187
187
  Description-Content-Type: text/markdown
188
188
  License-File: LICENSE
189
- Requires-Dist: aiohttp >=3.9.3
190
- Requires-Dist: ntgcalls >=1.2.0
189
+ Requires-Dist: aiohttp>=3.9.3
190
+ Requires-Dist: ntgcalls>=1.2.2
191
191
  Requires-Dist: psutil
192
192
  Requires-Dist: screeninfo
193
193
  Requires-Dist: deprecation
194
194
  Provides-Extra: hydrogram
195
- Requires-Dist: hydrogram >=0.1.4 ; extra == 'hydrogram'
195
+ Requires-Dist: hydrogram>=0.1.4; extra == "hydrogram"
196
196
  Provides-Extra: pyrogram
197
- Requires-Dist: pyrogram >=1.2.20 ; extra == 'pyrogram'
197
+ Requires-Dist: pyrogram>=1.2.20; extra == "pyrogram"
198
198
  Provides-Extra: telethon
199
- Requires-Dist: telethon >=1.24.0 ; extra == 'telethon'
199
+ Requires-Dist: telethon>=1.24.0; extra == "telethon"
200
200
 
201
201
  <img src="https://raw.githubusercontent.com/pytgcalls/pytgcalls/master/.github/images/banner.png" alt="pytgcalls logo" />
202
202
  <p align="center">
@@ -1,8 +1,8 @@
1
1
  pytgcalls/__init__.py,sha256=TfZGf1enqqs50mBB406vygB6zYgn3vAjBYFUDO4Pviw,248
2
- pytgcalls/__version__.py,sha256=HVx0XJJ9OYFWBBPBCUFYb8Nm43ChPg9GZLh_dkxh9qI,22
2
+ pytgcalls/__version__.py,sha256=fcRMgwI40iVFwre_3iKQA-N6sHUo3pAErXcKJS63DRg,22
3
3
  pytgcalls/environment.py,sha256=ctCHACvG6l8SdpPewSBhOvc70kbwpv18maC0TwLvZ08,1924
4
4
  pytgcalls/exceptions.py,sha256=0MmAktc53ajYAc7ThjD2tJ9PDyibUi0iHZMfUy2IoKs,4109
5
- pytgcalls/ffmpeg.py,sha256=sut7ssGcvprC3NWFpCfyguyNKAXaeM0mv3lXSvDPRpM,8518
5
+ pytgcalls/ffmpeg.py,sha256=uAqFDPwWoABW_WfubxeulpIh5vWpylxFARgYokn3ff8,8640
6
6
  pytgcalls/filters.py,sha256=HFMBBbo_NCw6wqTtseHoDRsspJHQ49BUHBA1cxm7u4g,4852
7
7
  pytgcalls/mtproto_required.py,sha256=6B-31p5qH_6oekUgypV4nK3hqPS6Nr-pA8S81wjnbaY,630
8
8
  pytgcalls/mutex.py,sha256=Frjji5Ctzlk4AXEBuBLnDK-7HbtreoV6zuyKpFpMNI4,236
@@ -12,26 +12,26 @@ pytgcalls/scaffold.py,sha256=LihXRBl1kSqJSQvEoH5rAXJXrbnnIqSMBYrhXpW5hHs,958
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
15
- pytgcalls/ytdlp.py,sha256=VqeWts_jgPJTmcOM5_rckuKEOA0N2FujaBWvX3CyXE0,2196
15
+ pytgcalls/ytdlp.py,sha256=jRA-mKQEXleWvaoGv9wtMa77aRjxsyQxn6_0tXI3-sA,2435
16
16
  pytgcalls/custom_api/__init__.py,sha256=ZT8d0lc2YrDuw_YSFAXXHHMewoXGFZ-ANOBIAr0vGFQ,60
17
17
  pytgcalls/custom_api/custom_api.py,sha256=Ko3aS6psrwPmOhRPxvG0fepXt4STrA0StvINSxz4Cj8,1890
18
18
  pytgcalls/handlers/__init__.py,sha256=pubbxI4pLqQpAKf8-toD6ija4cpSvbCJOQFjTiDjX1E,75
19
- pytgcalls/handlers/handlers_holder.py,sha256=eDCRF6-zPSUmBb8ZuAPiJfgDvg2Qv6efdX6GlOXHxTA,1033
19
+ pytgcalls/handlers/handlers_holder.py,sha256=ve83ydtKM5BjhsQmQ3mridD-3RnSVEi05-oDeiWv28w,1176
20
20
  pytgcalls/media_devices/__init__.py,sha256=H6uUA6akUqp8WCiT2gLrqUtFdqpd9rcfqDviP5Vhrls,183
21
21
  pytgcalls/media_devices/device_info.py,sha256=KueJCRVXXDcxQJzoGfkzcD2kL58pkMUn7Fr3aUwnNtQ,489
22
- pytgcalls/media_devices/media_devices.py,sha256=0zCst7GzMHg9QyvNwGUyuveFzfvwUGEGfU8RrLnFH_I,3149
22
+ pytgcalls/media_devices/media_devices.py,sha256=KG4fKfubpeMQZVm9IuQmzDaLhsvKzKRdE3zIYRAhEHM,3227
23
23
  pytgcalls/media_devices/screen_info.py,sha256=ARD5nQoYDUt1rU-kOK8G5O5byGXGeFbZWWdDswdCDHc,1107
24
24
  pytgcalls/methods/__init__.py,sha256=hk1blAT5u_Isemdrg0nqInLsdRzTTZnak5NdAfkBPAk,217
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=gKUAzvha1RpvbtSI_n-GlBQkOONxzibCaCr4aA17Mag,567
28
- pytgcalls/methods/calls/leave_call.py,sha256=UQ3H0a5W4OmQF3KTtoaE0qYqRhqRD-npcAzWWGDbGQs,1256
28
+ pytgcalls/methods/calls/leave_call.py,sha256=e3lYJKFD29Qg1qgolmLKUk9_X1uApOT1pGYF8ZgwMqQ,1369
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
32
  pytgcalls/methods/stream/mute_stream.py,sha256=auo2aAazfEC90Ab6MzaiPdddiJ1w4fN_9HaORkAeOBY,570
33
33
  pytgcalls/methods/stream/pause_stream.py,sha256=z_AIWABrQMHmTwvlah_PrH9EjXbro8gKxZni4Km5ICg,573
34
- pytgcalls/methods/stream/play.py,sha256=wU4WKEp4cMfJPVDW-aug69HrzXrMJHCKkqrv-pCxQkg,7307
34
+ pytgcalls/methods/stream/play.py,sha256=38eWJSXFYgq7VRm4AH6e1NJfe6nYTyJ71PbK3mFijHs,7280
35
35
  pytgcalls/methods/stream/played_time.py,sha256=IkUdyHrqpzpRl9uf0uZhg1COo4zsHnQOPu3nipjVatI,570
36
36
  pytgcalls/methods/stream/resume_stream.py,sha256=z_DgP4cDExjEqEeX_ZL--50MXQ9lrATK876SIwE71PQ,576
37
37
  pytgcalls/methods/stream/unmute_stream.py,sha256=KUMhfMbhsPmZsmpF4cGWC1FVW7YwXha2MmQnqrBhM8s,576
@@ -44,49 +44,50 @@ pytgcalls/methods/utilities/idle.py,sha256=MDdzHTv1ws2yBhsvhBUnssGdghkZ2KwR0HUCP
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=yPCb8wQ-0I-5HjY_uC0DNqnPOa64hTWP4lkcAqG4rbc,8924
47
+ pytgcalls/methods/utilities/start.py,sha256=7mHp6RkfhuYC6i0JYmQvxK4KYRmkcvOs9kSrClPhNnk,9342
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
50
  pytgcalls/mtproto/bridged_client.py,sha256=kK22n-CKjtfmtNE6bXCpuL6kWAUK2_Ul7cGgx_HNuHQ,4975
51
51
  pytgcalls/mtproto/client_cache.py,sha256=1yA5CFAmWZUsWdpqk5vlaN3j1RV1rIN-X7EcqmsnlfY,5087
52
- pytgcalls/mtproto/hydrogram_client.py,sha256=iSqwvK8yZZCYMmFQOSXpcDwZOFrBGt-3vJUMyxar-Sc,21116
52
+ pytgcalls/mtproto/hydrogram_client.py,sha256=x0s0ZmD_cVT_TtEUIT5qO0OueZg719TkfyraaUWJze0,21290
53
53
  pytgcalls/mtproto/mtproto_client.py,sha256=LO71RqgxZ3bYxSFb6l9cc4ks6_peyqHN4i_z478c7yw,6883
54
- pytgcalls/mtproto/pyrogram_client.py,sha256=iyJMJo6iTULfmGh-jdfJgu8DNVFxzOn28A5_E7uH4-Q,21305
55
- pytgcalls/mtproto/telethon_client.py,sha256=8BkYncXnPUIJRgrhUBnMIlXV2_fm6vLkN8URVaSuow4,20207
54
+ pytgcalls/mtproto/pyrogram_client.py,sha256=oXKEoChpEpt3xS1NuM3rfXbmFcpWgBFyibgqm_Pp6D4,21479
55
+ pytgcalls/mtproto/telethon_client.py,sha256=j2Ybibhg67IL8M2LXBWXIJwpc6dTDMz5_9MRYsOVcuw,20373
56
56
  pytgcalls/types/__init__.py,sha256=yJVJZoH9M9u9VgpZGUX-MF4NzE-vKp4KrId21YQbcGE,910
57
57
  pytgcalls/types/browsers.py,sha256=47Kr5q96n4Q4WvVhA6IUlS2egEcA9GRLlDeFcQYyc9M,9545
58
58
  pytgcalls/types/cache.py,sha256=FfsOcmYnsBGPlJoTPIXXYcUSpGE3rhx6cjIH77hyUL0,1059
59
59
  pytgcalls/types/dict.py,sha256=lAo9hu4VlVJa9S7P8Y81BYmKtvz0rH7hwpGcH3ynHUw,78
60
+ pytgcalls/types/flag.py,sha256=dQPcQmTgTQzcOLTvGe8t_e9mY4qsVnCZFrrTk17b2Xw,132
60
61
  pytgcalls/types/list.py,sha256=UjP_XxxMpPkLlu6yEy29JYqOM5VITFwwJcDm0wZni1c,78
61
62
  pytgcalls/types/participant_list.py,sha256=LmGjU63MK1v3SS2_4xNbk04OOjmukNdAXYLRn2L-730,916
62
63
  pytgcalls/types/py_object.py,sha256=VlazuMP0cFpExKimW8BtWR66LDewnNdQSLC7r_t7JIM,842
63
64
  pytgcalls/types/update.py,sha256=wPCzWLhrsScZ3ksRTyt8IuDaaG5YI-ItG_Yw-OqzK2Y,157
64
65
  pytgcalls/types/user_agent.py,sha256=sSfeGqUe0v0wqBgdVszNFK0iOC_0Tdyto9CglBXlY4U,1086
65
66
  pytgcalls/types/calls/__init__.py,sha256=6O2wp7I3d2YGLNeMgXTRyG37Y6BESafneLdr9n37_4s,346
66
- pytgcalls/types/calls/call.py,sha256=JX05F5iD0kMuYOugpuCCilqtP-PEJp2MY3a_wWumtls,725
67
+ pytgcalls/types/calls/call.py,sha256=wxa3L3nZnbTKtZbezCaA3iUt4rZ5IriQyMMrgRlp7GA,485
67
68
  pytgcalls/types/calls/call_config.py,sha256=b6P43YTGF2t7E2CyD1mSYPJDUBvYYeHoxB3hSbTVyOY,120
68
69
  pytgcalls/types/calls/call_data.py,sha256=-qPj2QhWv32Xs7LyFQY4hiWDqJ21B8VBvdzREK8bDvY,544
69
70
  pytgcalls/types/calls/call_protocol.py,sha256=OVIQs1VgdY-DWbZbNr41hjLA4pGQvHx8Rgom1_NhJxQ,408
70
71
  pytgcalls/types/calls/group_call_config.py,sha256=auKH-hZJWj8PhTkyeQ_VK2z9NpNvNC7Scl_IhEUMnQM,353
71
72
  pytgcalls/types/calls/raw_call_update.py,sha256=hpNw6HrTW8Z36Lh2HinS-wzprryRtsIxyIFbIfjGgeI,795
72
73
  pytgcalls/types/chats/__init__.py,sha256=v8pUp_vbr2kQpyHtAQc80N-YqzmXHe9SbllUsa6njkU,261
73
- pytgcalls/types/chats/chat_update.py,sha256=U_8YSMdrx10ARormhwdbnZt-GQ1rjlLOKK4Vog9duCg,738
74
- pytgcalls/types/chats/group_call_participant.py,sha256=G5PEQjemkz8YFXaRuG_Q91QfGGixAKPT75nFDiAbYPY,1018
74
+ pytgcalls/types/chats/chat_update.py,sha256=wh8v2I-pZxJWGNBjIwWRbhY-ZCI4v8qGabDTpuJaHu0,619
75
+ pytgcalls/types/chats/group_call_participant.py,sha256=HQ2EVZKE1_uEjtUKdUA8yJemdc189IN4mioSP-KDEiY,1020
75
76
  pytgcalls/types/chats/updated_group_call_participant.py,sha256=-KID-z-4e43fhYWQp0pNMKPfmZizbJHXyzn6yLtIGNg,291
76
77
  pytgcalls/types/raw/__init__.py,sha256=ROHsKFeUMUtlFbx2rhfrdB-TuVm0zBuvNo29Ccn5614,308
77
78
  pytgcalls/types/raw/audio_parameters.py,sha256=1DsBPwdn_Ukd2Tbkb3whP_ILo9xJY_3XNNmbO4_NO9Q,449
78
79
  pytgcalls/types/raw/audio_stream.py,sha256=wEMa93hHt0VBUSuS6gPJlFIGZp5GdNU94O2C2u4AXnY,476
79
80
  pytgcalls/types/raw/stream.py,sha256=jCvFUSAdHupqMqfG1E36CgKijKoy0o2LUbgcVjj5Mz0,491
80
- pytgcalls/types/raw/video_parameters.py,sha256=LXBpdaw5vyNayVfgtmF-gRkCY_ATwAnunRDs75FQJTw,545
81
+ pytgcalls/types/raw/video_parameters.py,sha256=nUl9gkfYTVU0iLNGTtlZ5cZg8K6F7odIi9n8POJXCK4,639
81
82
  pytgcalls/types/raw/video_stream.py,sha256=2Chrk7NFWF1H9V7hH71RZ5rF3iBhT53syFkHKw4-5gc,433
82
83
  pytgcalls/types/stream/__init__.py,sha256=xfF-9ZulOLk3E6G1nw1Ky0ZRWXlFuER0Uj8HQn3650w,338
83
84
  pytgcalls/types/stream/audio_quality.py,sha256=4X94ErmTeLP4TVcE3eLtPPdtluSPxgxbgTosuNJOVhc,141
84
- pytgcalls/types/stream/media_stream.py,sha256=vH32FrwdMSA9-S54bvessVHewh_l-5WXqupQE8pe-x4,8979
85
+ pytgcalls/types/stream/media_stream.py,sha256=YoG-vISvDga1n4IHs4hdF03ldtqyojFMvwB3To_39kE,8931
85
86
  pytgcalls/types/stream/stream_audio_ended.py,sha256=2_EFa98F0vWu0d0jBmLtzp4NH_xBkDO_6yP9UtyKuCs,164
86
87
  pytgcalls/types/stream/stream_video_ended.py,sha256=9YFTTZPMDpB95eb815rGtgDrzBGfTeazJ5mZwP6Hvks,164
87
88
  pytgcalls/types/stream/video_quality.py,sha256=HBfWq005kh-D19MaVE9VzVdnODzrXf4IJUimCfslfiU,231
88
- py_tgcalls-2.0.1.dist-info/LICENSE,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
89
- py_tgcalls-2.0.1.dist-info/METADATA,sha256=i2DwDASj0BIS6txxb8o3zDrnOgZs74v7LTZD4y0qzcU,14357
90
- py_tgcalls-2.0.1.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
91
- py_tgcalls-2.0.1.dist-info/top_level.txt,sha256=IUDUwn0KkcbUYZbCe9R5AUb2Ob-lmllNUGQqyeXXd8A,10
92
- py_tgcalls-2.0.1.dist-info/RECORD,,
89
+ py_tgcalls-2.0.3.dist-info/LICENSE,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
90
+ py_tgcalls-2.0.3.dist-info/METADATA,sha256=0uu5GSvIXH0bc_1fZt1N8WWlN8Hx_Kmn-v3z2V0hd3w,14349
91
+ py_tgcalls-2.0.3.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
92
+ py_tgcalls-2.0.3.dist-info/top_level.txt,sha256=IUDUwn0KkcbUYZbCe9R5AUb2Ob-lmllNUGQqyeXXd8A,10
93
+ py_tgcalls-2.0.3.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.43.0)
2
+ Generator: setuptools (74.1.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
pytgcalls/__version__.py CHANGED
@@ -1 +1 @@
1
- __version__ = '2.0.1'
1
+ __version__ = '2.0.3'
pytgcalls/ffmpeg.py CHANGED
@@ -95,7 +95,10 @@ async def check_stream(
95
95
  new_w = min(original_width, stream_parameters.width)
96
96
  new_h = int(new_w / ratio)
97
97
 
98
- if new_h > stream_parameters.height:
98
+ if (
99
+ new_h > stream_parameters.height and
100
+ stream_parameters.adjust_by_height
101
+ ):
99
102
  new_h = stream_parameters.height
100
103
  new_w = int(new_h * ratio)
101
104
 
@@ -282,6 +285,8 @@ def _build_ffmpeg_options(
282
285
  options.extend([
283
286
  'rawvideo',
284
287
  '-r', str(stream_parameters.frame_rate),
288
+ '-pix_fmt',
289
+ 'yuv420p',
285
290
  '-vf',
286
291
  f'scale={stream_parameters.width}:{stream_parameters.height}',
287
292
  ])
@@ -41,3 +41,9 @@ class HandlersHolder:
41
41
  ) -> Callable:
42
42
  self._callbacks.append(Callback(func, filters))
43
43
  return func
44
+
45
+ def remove_handler(
46
+ self,
47
+ func: Callable,
48
+ ):
49
+ self._callbacks = [x for x in self._callbacks if x.func != func]
@@ -72,9 +72,11 @@ class MediaDevices:
72
72
  except subprocess.TimeoutExpired:
73
73
  return list_devices
74
74
  if platform == 'win32':
75
- list_raw = result.split('DirectShow audio devices')[1]
75
+ list_raw = result.split('DirectShow audio devices')
76
+ if len(list_raw) < 2:
77
+ return list_devices
76
78
  output = re.findall(
77
- '\\[.*?].*?"(.*?)".*?\n\\[.*?].*?"(.*?)"', list_raw,
79
+ '\\[.*?].*?"(.*?)".*?\n\\[.*?].*?"(.*?)"', list_raw[1],
78
80
  )
79
81
  for device in output:
80
82
  list_devices.append(
@@ -19,6 +19,15 @@ class LeaveCall(Scaffold):
19
19
  chat_id: Union[int, str],
20
20
  ):
21
21
  chat_id = await self.resolve_chat_id(chat_id)
22
+ is_p2p_waiting = (
23
+ chat_id in self._p2p_configs and
24
+ not self._p2p_configs[chat_id].wait_data.done()
25
+ )
26
+ if not is_p2p_waiting:
27
+ try:
28
+ await self._binding.stop(chat_id)
29
+ except ConnectionNotFound:
30
+ raise NotInCallError()
22
31
  if chat_id < 0: # type: ignore
23
32
  chat_call = await self._app.get_full_chat(
24
33
  chat_id,
@@ -32,13 +41,8 @@ class LeaveCall(Scaffold):
32
41
  )
33
42
  else:
34
43
  await self._app.discard_call(chat_id)
35
- if chat_id in self._p2p_configs and \
36
- not self._p2p_configs[chat_id].outgoing:
44
+ if is_p2p_waiting:
37
45
  self._p2p_configs.pop(chat_id)
38
46
  return
39
- try:
40
- await self._binding.stop(chat_id)
41
- except ConnectionNotFound:
42
- raise NotInCallError()
43
47
  if chat_id < 0: # type: ignore
44
48
  self._need_unmute.discard(chat_id)
@@ -52,7 +52,7 @@ class Play(Scaffold):
52
52
  try:
53
53
  return await self._binding.change_stream(
54
54
  chat_id,
55
- await StreamParams.get_stream_params(stream),
55
+ media_description,
56
56
  )
57
57
  except FileError as e:
58
58
  raise FileNotFoundError(e)
@@ -90,7 +90,14 @@ class Start(Scaffold):
90
90
  ) == participant.user_id if chat_peer else False
91
91
  if is_self:
92
92
  if action == GroupCallParticipant.Action.LEFT:
93
- await clear_call(chat_id)
93
+ if await clear_call(chat_id):
94
+ await self.propagate(
95
+ ChatUpdate(
96
+ chat_id,
97
+ ChatUpdate.Status.KICKED,
98
+ ),
99
+ self,
100
+ )
94
101
  if (
95
102
  chat_id in self._need_unmute and
96
103
  action == GroupCallParticipant.Action.UPDATED and
@@ -117,12 +124,15 @@ class Start(Scaffold):
117
124
  self,
118
125
  )
119
126
 
120
- async def clear_call(chat_id):
127
+ async def clear_call(chat_id) -> bool:
128
+ res = False
121
129
  try:
122
130
  await self._binding.stop(chat_id)
131
+ res = True
123
132
  except ConnectionNotFound:
124
133
  pass
125
134
  await clear_cache(chat_id)
135
+ return res
126
136
 
127
137
  async def update_status(chat_id: int, state: MediaState):
128
138
  try:
@@ -78,7 +78,7 @@ class HydrogramClient(BridgedClient):
78
78
  self,
79
79
  )
80
80
 
81
- @self._app.on_raw_update()
81
+ @self._app.on_raw_update(group=-1)
82
82
  async def on_update(_, update, __, chats):
83
83
  if isinstance(
84
84
  update,
@@ -353,19 +353,24 @@ class HydrogramClient(BridgedClient):
353
353
  self,
354
354
  input_call: InputGroupCall,
355
355
  ) -> List[GroupCallParticipant]:
356
+ participants = []
357
+ next_offset = ''
358
+ while True:
359
+ result = await self._app.invoke(
360
+ GetGroupParticipants(
361
+ call=input_call,
362
+ ids=[],
363
+ sources=[],
364
+ offset=next_offset,
365
+ limit=0,
366
+ ),
367
+ )
368
+ participants.extend(result.participants)
369
+ if not (next_offset := result.next_offset):
370
+ break
356
371
  return [
357
372
  self.parse_participant(participant)
358
- for participant in (
359
- await self._app.invoke(
360
- GetGroupParticipants(
361
- call=input_call,
362
- ids=[],
363
- sources=[],
364
- offset='',
365
- limit=500,
366
- ),
367
- )
368
- ).participants
373
+ for participant in participants
369
374
  ]
370
375
 
371
376
  async def join_group_call(
@@ -86,7 +86,7 @@ class PyrogramClient(BridgedClient):
86
86
  self,
87
87
  )
88
88
 
89
- @self._app.on_raw_update()
89
+ @self._app.on_raw_update(group=-1)
90
90
  async def on_update(_, update, __, chats):
91
91
  if isinstance(
92
92
  update,
@@ -361,19 +361,24 @@ class PyrogramClient(BridgedClient):
361
361
  self,
362
362
  input_call: InputGroupCall,
363
363
  ) -> List[GroupCallParticipant]:
364
+ participants = []
365
+ next_offset = ''
366
+ while True:
367
+ result = await self._app.send(
368
+ GetGroupParticipants(
369
+ call=input_call,
370
+ ids=[],
371
+ sources=[],
372
+ offset=next_offset,
373
+ limit=0,
374
+ ),
375
+ )
376
+ participants.extend(result.participants)
377
+ if not (next_offset := result.next_offset):
378
+ break
364
379
  return [
365
380
  self.parse_participant(participant)
366
- for participant in (
367
- await self._app.send(
368
- GetGroupParticipants(
369
- call=input_call,
370
- ids=[],
371
- sources=[],
372
- offset='',
373
- limit=500,
374
- ),
375
- )
376
- ).participants
381
+ for participant in participants
377
382
  ]
378
383
 
379
384
  async def join_group_call(
@@ -330,19 +330,24 @@ class TelethonClient(BridgedClient):
330
330
  self,
331
331
  input_call: InputGroupCall,
332
332
  ) -> List[GroupCallParticipant]:
333
+ participants = []
334
+ next_offset = ''
335
+ while True:
336
+ result = await self._app(
337
+ GetGroupParticipantsRequest(
338
+ call=input_call,
339
+ ids=[],
340
+ sources=[],
341
+ offset=next_offset,
342
+ limit=0,
343
+ ),
344
+ )
345
+ participants.extend(result.participants)
346
+ if not (next_offset := result.next_offset):
347
+ break
333
348
  return [
334
349
  self.parse_participant(participant)
335
- for participant in (
336
- await self._app(
337
- GetGroupParticipantsRequest(
338
- call=input_call,
339
- ids=[],
340
- sources=[],
341
- offset='',
342
- limit=500,
343
- ),
344
- )
345
- ).participants
350
+ for participant in participants
346
351
  ]
347
352
 
348
353
  async def join_group_call(
@@ -1,7 +1,7 @@
1
1
  from enum import auto
2
- from enum import Flag
3
2
 
4
3
  from ...types.py_object import PyObject
4
+ from ..flag import Flag
5
5
 
6
6
 
7
7
  class Call(PyObject):
@@ -10,18 +10,10 @@ class Call(PyObject):
10
10
  PAUSED = auto()
11
11
  IDLE = auto()
12
12
 
13
- def __repr__(self):
14
- cls_name = self.__class__.__name__
15
- return f'{cls_name}.{self.name}'
16
-
17
13
  class Type(Flag):
18
14
  GROUP = auto()
19
15
  PRIVATE = auto()
20
16
 
21
- def __repr__(self):
22
- cls_name = self.__class__.__name__
23
- return f'{cls_name}.{self.name}'
24
-
25
17
  def __init__(
26
18
  self,
27
19
  chat_id: int,
@@ -1,7 +1,7 @@
1
1
  from enum import auto
2
- from enum import Flag
3
2
  from typing import Any
4
3
 
4
+ from ..flag import Flag
5
5
  from ..update import Update
6
6
 
7
7
 
@@ -15,10 +15,6 @@ class ChatUpdate(Update):
15
15
  INCOMING_CALL = auto()
16
16
  LEFT_CALL = KICKED | LEFT_GROUP | CLOSED_VOICE_CHAT | DISCARDED_CALL
17
17
 
18
- def __repr__(self):
19
- cls_name = self.__class__.__name__
20
- return f'{cls_name}.{self.name}'
21
-
22
18
  def __init__(
23
19
  self,
24
20
  chat_id: int,
@@ -1,7 +1,7 @@
1
1
  from enum import auto
2
- from enum import Flag
3
2
 
4
3
  from ...types.py_object import PyObject
4
+ from ..flag import Flag
5
5
 
6
6
 
7
7
  class GroupCallParticipant(PyObject):
@@ -0,0 +1,6 @@
1
+ from enum import Flag as _Flag
2
+
3
+
4
+ class Flag(_Flag):
5
+ def __repr__(self):
6
+ return f'{self.__class__.__name__}.{self.name}'
@@ -10,6 +10,7 @@ class VideoParameters(PyObject):
10
10
  width: int = 640,
11
11
  height: int = 360,
12
12
  frame_rate: int = 20,
13
+ adjust_by_height: bool = True,
13
14
  ):
14
15
  max_w, max_h, max_fps = max(
15
16
  VideoQuality, key=lambda x: x.value[0],
@@ -17,3 +18,4 @@ class VideoParameters(PyObject):
17
18
  self.width: int = min(width, max_w)
18
19
  self.height: int = min(height, max_h)
19
20
  self.frame_rate: int = min(frame_rate, max_fps)
21
+ self.adjust_by_height: bool = adjust_by_height
@@ -1,5 +1,4 @@
1
1
  from enum import auto
2
- from enum import Flag
3
2
  from pathlib import Path
4
3
  from typing import Dict
5
4
  from typing import Optional
@@ -17,6 +16,7 @@ from ...media_devices import DeviceInfo
17
16
  from ...media_devices import ScreenInfo
18
17
  from ...statictypes import statictypes
19
18
  from ...ytdlp import YtDlp
19
+ from ..flag import Flag
20
20
  from ..raw.audio_parameters import AudioParameters
21
21
  from ..raw.audio_stream import AudioStream
22
22
  from ..raw.stream import Stream
@@ -33,10 +33,6 @@ class MediaStream(Stream):
33
33
  IGNORE = auto()
34
34
  NO_LATENCY = auto()
35
35
 
36
- def __repr__(self):
37
- cls_name = self.__class__.__name__
38
- return f'{cls_name}.{self.name}'
39
-
40
36
  @statictypes
41
37
  def __init__(
42
38
  self,
@@ -66,7 +62,10 @@ class MediaStream(Stream):
66
62
  if isinstance(video_parameters, VideoParameters):
67
63
  self._video_parameters = video_parameters
68
64
  elif isinstance(video_parameters, VideoQuality):
69
- self._video_parameters = VideoParameters(*video_parameters.value)
65
+ self._video_parameters = VideoParameters(
66
+ *video_parameters.value,
67
+ adjust_by_height=False,
68
+ )
70
69
 
71
70
  self._media_path: Optional[str] = None
72
71
  self._audio_path: Optional[str] = None
pytgcalls/ytdlp.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import asyncio
2
+ import logging
2
3
  import re
3
4
  import shlex
4
5
  from typing import Optional
@@ -8,6 +9,8 @@ from .exceptions import YtDlpError
8
9
  from .ffmpeg import cleanup_commands
9
10
  from .types.raw import VideoParameters
10
11
 
12
+ py_logger = logging.getLogger('pytgcalls')
13
+
11
14
 
12
15
  class YtDlp:
13
16
  YOUTUBE_REGX = re.compile(
@@ -34,8 +37,10 @@ class YtDlp:
34
37
  'yt-dlp',
35
38
  '-g',
36
39
  '-f',
37
- f'best[width<=?{video_parameters.width}]'
38
- f'[height<=?{video_parameters.height}]',
40
+ 'bestvideo[vcodec~=\'(vp09|avc1)\']+m4a/best',
41
+ '-S',
42
+ 'res:'
43
+ f'{min(video_parameters.width, video_parameters.height)}',
39
44
  '--no-warnings',
40
45
  ]
41
46
 
@@ -52,6 +57,10 @@ class YtDlp:
52
57
 
53
58
  commands.append(link)
54
59
 
60
+ py_logger.log(
61
+ logging.DEBUG,
62
+ f'Running with "{" ".join(commands)}" command',
63
+ )
55
64
  try:
56
65
  proc = await asyncio.create_subprocess_exec(
57
66
  *commands,