py-tgcalls 2.1.2b2__py3-none-any.whl → 2.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. {py_tgcalls-2.1.2b2.dist-info → py_tgcalls-2.2.0.dist-info}/METADATA +2 -2
  2. {py_tgcalls-2.1.2b2.dist-info → py_tgcalls-2.2.0.dist-info}/RECORD +32 -31
  3. {py_tgcalls-2.1.2b2.dist-info → py_tgcalls-2.2.0.dist-info}/WHEEL +1 -1
  4. pytgcalls/__version__.py +1 -1
  5. pytgcalls/ffmpeg.py +2 -2
  6. pytgcalls/filters.py +6 -2
  7. pytgcalls/list_to_cmd.py +11 -0
  8. pytgcalls/methods/calls/leave_call.py +4 -0
  9. pytgcalls/methods/internal/connect_call.py +10 -1
  10. pytgcalls/methods/internal/handle_mtproto_updates.py +8 -15
  11. pytgcalls/methods/stream/play.py +2 -1
  12. pytgcalls/mtproto/bridged_client.py +64 -2
  13. pytgcalls/mtproto/client_cache.py +65 -72
  14. pytgcalls/mtproto/hydrogram_client.py +132 -35
  15. pytgcalls/mtproto/mtproto_client.py +11 -0
  16. pytgcalls/mtproto/pyrogram_client.py +135 -43
  17. pytgcalls/mtproto/telethon_client.py +95 -35
  18. pytgcalls/mutex.py +3 -1
  19. pytgcalls/types/cache.py +10 -5
  20. pytgcalls/types/chats/group_call_participant.py +1 -8
  21. pytgcalls/types/chats/updated_group_call_participant.py +2 -0
  22. pytgcalls/types/dict.py +1 -1
  23. pytgcalls/types/flag.py +4 -3
  24. pytgcalls/types/list.py +1 -1
  25. pytgcalls/types/participant_list.py +3 -3
  26. pytgcalls/types/py_object.py +4 -2
  27. pytgcalls/types/stream/media_stream.py +5 -4
  28. pytgcalls/types/stream/record_stream.py +3 -1
  29. pytgcalls/types/stream/video_quality.py +3 -1
  30. pytgcalls/ytdlp.py +3 -2
  31. {py_tgcalls-2.1.2b2.dist-info → py_tgcalls-2.2.0.dist-info}/licenses/LICENSE +0 -0
  32. {py_tgcalls-2.1.2b2.dist-info → py_tgcalls-2.2.0.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: py-tgcalls
3
- Version: 2.1.2b2
3
+ Version: 2.2.0
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<1.4.0,>=1.3.5b3
23
+ Requires-Dist: ntgcalls<3.0.0,>=2.0.0
24
24
  Requires-Dist: deprecation
25
25
  Provides-Extra: pyrogram
26
26
  Requires-Dist: pyrogram>=1.2.20; extra == "pyrogram"
@@ -1,12 +1,13 @@
1
- py_tgcalls-2.1.2b2.dist-info/licenses/LICENSE,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
1
+ py_tgcalls-2.2.0.dist-info/licenses/LICENSE,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
2
2
  pytgcalls/__init__.py,sha256=qbfwN7rYwIdCegMOzdcbvwazeNjDzgmowgcqLFNqKIM,308
3
- pytgcalls/__version__.py,sha256=FprLafBuvz-hzBW23aNWsGkjU3pSVyK0rnV3nOorhlc,24
3
+ pytgcalls/__version__.py,sha256=Vyf6P6UCZKFeQtRzYujPmFfdlqSfnc01VEMWE3O0ZrA,22
4
4
  pytgcalls/environment.py,sha256=ctCHACvG6l8SdpPewSBhOvc70kbwpv18maC0TwLvZ08,1924
5
5
  pytgcalls/exceptions.py,sha256=Rijc-8T93WEWJxNW9jncU8_M6mYZZZcs8F2bqitEIeI,3787
6
- pytgcalls/ffmpeg.py,sha256=tm6DBxyNfPh3h3an-b2s9x1UyX-cvkCdov9prlXxVZY,8649
7
- pytgcalls/filters.py,sha256=qTFDlt-23xnMh_Ug2WmmOUf13JPX6_yacrv7c3F9Pp0,6125
6
+ pytgcalls/ffmpeg.py,sha256=CZvSyuztc-TGKbKI9_2G7CLITe1ITf315YPyprWu_Pg,8645
7
+ pytgcalls/filters.py,sha256=8Fq_gvHHdqhIk_XwMJ9wneeZOwrvBkSOKaMJ60r3bZU,6157
8
+ pytgcalls/list_to_cmd.py,sha256=rGJLsejbAQdDb8pctMbLnwea5NkitlfVKc3IpoGi4V4,240
8
9
  pytgcalls/mtproto_required.py,sha256=6B-31p5qH_6oekUgypV4nK3hqPS6Nr-pA8S81wjnbaY,630
9
- pytgcalls/mutex.py,sha256=6hOwGnUTNUJliJ1GGhk47D0A3KEn8eVd-kjZq_1DdZY,670
10
+ pytgcalls/mutex.py,sha256=vWqji9IAHtAc61FUTVXncx5rZ3rVf5qG_7PI4LmuYmU,733
10
11
  pytgcalls/pytgcalls.py,sha256=DxCE0--mb53vyDXLLBAwy1cPrJgLsyC9rba_h2OzR2o,1608
11
12
  pytgcalls/pytgcalls_session.py,sha256=_BGJWvf7t3mki2DhlEPjh9cypvYuSFkMSxzTsfepwUk,2719
12
13
  pytgcalls/scaffold.py,sha256=Gahln5l70FJZwo1KGqv1A7K9Vn_ozAATpADGFJuPhKA,3162
@@ -14,7 +15,7 @@ pytgcalls/statictypes.py,sha256=CdlqgQNhTZ_uTE8-B8m01fJ7TlD2B42EI2QBPxDdAtA,3842
14
15
  pytgcalls/sync.py,sha256=IsOH3TD7cxUg_-zdGt12HoS8sBlXvcGayPZAoxxKM48,3396
15
16
  pytgcalls/version_manager.py,sha256=egeGgvb66zWlLTMuw2U-b0x8MfnRzMm1xAEVN87HF5c,296
16
17
  pytgcalls/wait_counter_lock.py,sha256=J-KCWUBCt7ktKQKyIseNG0RfXDVRh-h0wKhaZlf4aFs,437
17
- pytgcalls/ytdlp.py,sha256=jRA-mKQEXleWvaoGv9wtMa77aRjxsyQxn6_0tXI3-sA,2435
18
+ pytgcalls/ytdlp.py,sha256=MEPkVlFdbexbgqVRMt7C1YadPIER2R-4oN03osl5vq8,2473
18
19
  pytgcalls/custom_api/__init__.py,sha256=ZT8d0lc2YrDuw_YSFAXXHHMewoXGFZ-ANOBIAr0vGFQ,60
19
20
  pytgcalls/custom_api/custom_api.py,sha256=Ko3aS6psrwPmOhRPxvG0fepXt4STrA0StvINSxz4Cj8,1890
20
21
  pytgcalls/handlers/__init__.py,sha256=pubbxI4pLqQpAKf8-toD6ija4cpSvbCJOQFjTiDjX1E,75
@@ -29,16 +30,16 @@ pytgcalls/methods/__init__.py,sha256=KKnG3uI_3oKKBByQ96kHJiabjxk2J6YLs4HDfOKvQ0A
29
30
  pytgcalls/methods/calls/__init__.py,sha256=xg4DZZClEnxwaj-DAq3e8gSR-g-MiYBdUEBth64lSXA,214
30
31
  pytgcalls/methods/calls/change_volume_call.py,sha256=xMUszg44Gs1RgTXGCwcWEESnwu3XVkW8Kx9HGLDGSEo,842
31
32
  pytgcalls/methods/calls/get_participants.py,sha256=HDEMwZwNZM7KSb76P5XVH46qNONvBEVg4x_e-rgJscI,716
32
- pytgcalls/methods/calls/leave_call.py,sha256=Q7v0xT_CjbMIUBrugtvKbZqbSgmw5laMQYVhrMcaD1U,1475
33
+ pytgcalls/methods/calls/leave_call.py,sha256=YxeCB6mq5OhIy5MoFuC2PgKQ2H0E8VGr4I79upC5URY,1603
33
34
  pytgcalls/methods/decorators/__init__.py,sha256=TCGaEVZnHjtOwv-3PNfaCVm0kyFhJApUPUNntt6MwyM,78
34
35
  pytgcalls/methods/decorators/on_update.py,sha256=ZTL4YcQk0N4Ru56a5WItUvkSN5SAqr6_RDZvXmZMIHs,316
35
36
  pytgcalls/methods/internal/__init__.py,sha256=fcgIxUJKT6QJD30ltnOfzKsLhzTTTklD2qxKlwCvyv0,1057
36
37
  pytgcalls/methods/internal/clear_cache.py,sha256=qgG-oubmdtnefnXSiHSPHyBTyXypiLDC7G8l3FzjNw8,236
37
38
  pytgcalls/methods/internal/clear_call.py,sha256=yElvn3i6_j14Q7n9kcLSl-muYAGcaIZaEFHdp6MrN0g,549
38
- pytgcalls/methods/internal/connect_call.py,sha256=2DRmsILPyGNxV2880tVsQ2XUwd89iSIqVWHl5AkgEaE,5393
39
+ pytgcalls/methods/internal/connect_call.py,sha256=Py-sB_ImH839tK9GxNUCJDJUNizsZtlm5m6kuiUX3lE,5739
39
40
  pytgcalls/methods/internal/emit_sig_data.py,sha256=ucIsknhJHB-0x7lcymXvwQ647AJQ852zH2W6MdlC3ws,216
40
41
  pytgcalls/methods/internal/handle_connection_changed.py,sha256=_1u3J6_Pjl1Gs1u_WkhG2FAUl_hxlHUiflaMkKkJDsc,866
41
- pytgcalls/methods/internal/handle_mtproto_updates.py,sha256=Ev2Jake6Z_SrBodnjO5N16YiYaEY3Ti4tkU1pKOsJVM,7747
42
+ pytgcalls/methods/internal/handle_mtproto_updates.py,sha256=ZPGvenIjWiNnTTTKdhQdapHsxwYn4pSKOgKm8bPcPOk,7415
42
43
  pytgcalls/methods/internal/handle_stream_ended.py,sha256=DllD1ZfGQbwVh-S0neocwnN-8lQtwwyrzWl9teSrZbY,561
43
44
  pytgcalls/methods/internal/handle_stream_frame.py,sha256=_FA782qlOT3tUqnySm7RBpjbgfEEzt1oEBDm-iADsbQ,1145
44
45
  pytgcalls/methods/internal/join_presentation.py,sha256=dLB2kolIIm2KQH8yBQbEPJi_y1_cVLWpE52_Rwjn_KE,2178
@@ -51,7 +52,7 @@ pytgcalls/methods/internal/update_status.py,sha256=6zH7oMM_qPE-88mdC5CBhT07gPvay
51
52
  pytgcalls/methods/stream/__init__.py,sha256=mAcOih0-NT6T_Gspej6mySpJNPuEe46sUwgKV3vSvYM,336
52
53
  pytgcalls/methods/stream/mute.py,sha256=ZrZS_EeNUeUxb6UgbdhwXUdRX826u-qSjH5a6sg7LsE,557
53
54
  pytgcalls/methods/stream/pause.py,sha256=-kNvWQuv5VlssNcL-M6rkT5TKFmXlbOzJrDny95qsUc,560
54
- pytgcalls/methods/stream/play.py,sha256=fTZS-XHF50Wo9BNOZ373n4YhGqRuu7uZR-GJEACjqYY,2935
55
+ pytgcalls/methods/stream/play.py,sha256=XJB7o4Y5ImY1Qh_tHCkT70cUKOr9JlinWtVKwE8W5Rw,2951
55
56
  pytgcalls/methods/stream/record.py,sha256=geYSVtSbp0yRIR1Nmj-L1s-6nqQAh0x0IcA1OuFvuyA,1306
56
57
  pytgcalls/methods/stream/resume.py,sha256=AUHU3AtpXO2rtp2V1EKSC_KAWTk2KHMiHaqHluYy31M,563
57
58
  pytgcalls/methods/stream/send_frame.py,sha256=Kj9R8OqUM-g7pt-FiWP-US7sCFkH5ciPr9S8v-WPtLg,1062
@@ -69,20 +70,20 @@ pytgcalls/methods/utilities/run.py,sha256=cnYQd2xB5Cr_WS0Q2cXJZPGiN6JOCULzj1r4xX
69
70
  pytgcalls/methods/utilities/start.py,sha256=mn0kQZhTUuc-9CCJDbFIVsEtJ8kfnfZOGbVC505qVRM,3232
70
71
  pytgcalls/methods/utilities/stream_params.py,sha256=fOSloo1A7WTxaZEtOiPXjdexMeoJjq8CZtfHuIFX7Ns,3325
71
72
  pytgcalls/mtproto/__init__.py,sha256=X4zvzFG7km7qHyE0fdvA550WcOVO_xl_p__gvIfDGmw,130
72
- pytgcalls/mtproto/bridged_client.py,sha256=svXufZkCj7WM9XOWkuk5oJVQxgL1Bg_8rz7w_ZKWlQg,6451
73
- pytgcalls/mtproto/client_cache.py,sha256=fpmZhRUGD3G2t2LjEK0z4OPLmWVhJQZUvDW6bgr6StI,5907
74
- pytgcalls/mtproto/hydrogram_client.py,sha256=pSEtHowL833-vD5ppm78eBe7_Ik0pumChbDTMLsyP5Y,25553
75
- pytgcalls/mtproto/mtproto_client.py,sha256=95A13HsNJfpNslsY_gWiqYXj_Vvo-pl3rVrsJGxftgg,8517
76
- pytgcalls/mtproto/pyrogram_client.py,sha256=linvRHAxZCb4PenJEN9-OtjQm7Go9OONyDotZcMydNY,25710
77
- pytgcalls/mtproto/telethon_client.py,sha256=iDMAAKvvFVigOrLPusG9ytiswxM2UCp4KZZuwtT-vKo,24987
73
+ pytgcalls/mtproto/bridged_client.py,sha256=Qb9-9FrUdh3g_sx-JOcvkzv3kJtS_pz2Qaos85DgVPI,8280
74
+ pytgcalls/mtproto/client_cache.py,sha256=5unu8sjLRaIKoEgJGaIRjhA4P3U2lFpfakTKFxKLzAM,5591
75
+ pytgcalls/mtproto/hydrogram_client.py,sha256=P2YpeIBYXzBHWLXyk9pGiO_TsIBuzDQ7LvorGZFFM-o,28974
76
+ pytgcalls/mtproto/mtproto_client.py,sha256=9SIG3DNeICIXvggyVE8DQWtToPtxV0t9ZKr6dEMnEMg,8783
77
+ pytgcalls/mtproto/pyrogram_client.py,sha256=CI9uPMdwwE3UGSNfenqIKUl-UD_caVZpCzYR1PB4drY,28970
78
+ pytgcalls/mtproto/telethon_client.py,sha256=w9PuqE_gsDKFYVpF5o_ULMSsYf5sAK8VgImVxbNz2Bc,27106
78
79
  pytgcalls/types/__init__.py,sha256=GlgBBXAwbNopXSeTTmiXktrEJhhN_rMBtuAllTBbN3k,1189
79
80
  pytgcalls/types/browsers.py,sha256=47Kr5q96n4Q4WvVhA6IUlS2egEcA9GRLlDeFcQYyc9M,9545
80
- pytgcalls/types/cache.py,sha256=FfsOcmYnsBGPlJoTPIXXYcUSpGE3rhx6cjIH77hyUL0,1059
81
- pytgcalls/types/dict.py,sha256=lAo9hu4VlVJa9S7P8Y81BYmKtvz0rH7hwpGcH3ynHUw,78
82
- pytgcalls/types/flag.py,sha256=dQPcQmTgTQzcOLTvGe8t_e9mY4qsVnCZFrrTk17b2Xw,132
83
- pytgcalls/types/list.py,sha256=UjP_XxxMpPkLlu6yEy29JYqOM5VITFwwJcDm0wZni1c,78
84
- pytgcalls/types/participant_list.py,sha256=LmGjU63MK1v3SS2_4xNbk04OOjmukNdAXYLRn2L-730,916
85
- pytgcalls/types/py_object.py,sha256=__GNXgffGK4jhdF4QPqIknd0k2myObJf_7fW3pNGpbU,836
81
+ pytgcalls/types/cache.py,sha256=nJh6B7xnvAiLh0mDJYS9sYhnRvj0BqxrQBLXs4WEUMs,1235
82
+ pytgcalls/types/dict.py,sha256=-R1v5-v5WzhquPN25Bfw9Ow6q2lRRgpsq_FlsOawCUw,78
83
+ pytgcalls/types/flag.py,sha256=MeWDKkUAZa97fUPg5Ni5Rf4pDgiZ_OSRZPseEY7d3rw,104
84
+ pytgcalls/types/list.py,sha256=rGzD9LWAI2hUX71OL_pqZn08YHEbZ-AZ6RTjXPc9wJA,78
85
+ pytgcalls/types/participant_list.py,sha256=wG7a8dvcmcUkagmSo-g4thGMBrqMdEU0fA_zD4tCk2w,931
86
+ pytgcalls/types/py_object.py,sha256=jisGKqJINuzAjkIkLIps61uYM0eFSmC9TtgxGRDAMZI,934
86
87
  pytgcalls/types/update.py,sha256=wPCzWLhrsScZ3ksRTyt8IuDaaG5YI-ItG_Yw-OqzK2Y,157
87
88
  pytgcalls/types/user_agent.py,sha256=sSfeGqUe0v0wqBgdVszNFK0iOC_0Tdyto9CglBXlY4U,1086
88
89
  pytgcalls/types/calls/__init__.py,sha256=lgFG89_NGhWHOQqhfw3adPaQZMzsMKI1f-MyZW3TBBU,478
@@ -96,8 +97,8 @@ pytgcalls/types/calls/pending_connection.py,sha256=qRRmutInj70rtzbThM7CNznFhEPqT
96
97
  pytgcalls/types/calls/raw_call_update.py,sha256=hpNw6HrTW8Z36Lh2HinS-wzprryRtsIxyIFbIfjGgeI,795
97
98
  pytgcalls/types/chats/__init__.py,sha256=v8pUp_vbr2kQpyHtAQc80N-YqzmXHe9SbllUsa6njkU,261
98
99
  pytgcalls/types/chats/chat_update.py,sha256=lzrqNDPv4a_yXpKIfUnhocXqZyIy8XgZladOQTYrrYA,730
99
- pytgcalls/types/chats/group_call_participant.py,sha256=XG4dekFV9GYHASqy_bSE6YnZ1uDunFFif-xLAy_eYGY,1711
100
- pytgcalls/types/chats/updated_group_call_participant.py,sha256=-KID-z-4e43fhYWQp0pNMKPfmZizbJHXyzn6yLtIGNg,291
100
+ pytgcalls/types/chats/group_call_participant.py,sha256=aK7nvI0Jy93g9A_FVeFzk1BZFXzhFry06h8xR4VpqXY,1507
101
+ pytgcalls/types/chats/updated_group_call_participant.py,sha256=bZQsZAsMv_i4k8DJW3phyuHqpa9Dp6IbheHCvj3M630,365
101
102
  pytgcalls/types/raw/__init__.py,sha256=ROHsKFeUMUtlFbx2rhfrdB-TuVm0zBuvNo29Ccn5614,308
102
103
  pytgcalls/types/raw/audio_parameters.py,sha256=1DsBPwdn_Ukd2Tbkb3whP_ILo9xJY_3XNNmbO4_NO9Q,449
103
104
  pytgcalls/types/raw/audio_stream.py,sha256=oN7Sx9oLbNFuNXiGYpoNabMwqWKGquLiHEywef28o7c,488
@@ -110,12 +111,12 @@ pytgcalls/types/stream/device.py,sha256=EdoDg6lPE7fgoZI04Nr0E9zbIk-iRIBgYYAzVqoC
110
111
  pytgcalls/types/stream/direction.py,sha256=VepLMe-dXg4M5eVdVyIb2uxYvnpB9OJL5fEgPYUFtTI,592
111
112
  pytgcalls/types/stream/external_media.py,sha256=RiuSX5tZGdNsQZ8LIRk5Lp4Ksv9oTvaccmInJRZYo4M,114
112
113
  pytgcalls/types/stream/frame.py,sha256=TXo5HZVHbbaVNBqulMhTqGODXH3bpBVlN_of1rosNUQ,586
113
- pytgcalls/types/stream/media_stream.py,sha256=_NJFTAIUdYyTh-gjiqs6aCpAIfSVjE16mBYUapMnDfg,11917
114
- pytgcalls/types/stream/record_stream.py,sha256=RWeD9U-sqUmb_PuZQxYnExZyoibepU_8oI2yrH2Y18c,3135
114
+ pytgcalls/types/stream/media_stream.py,sha256=zcRVpNXfL8mhg-SEfAi-f0lDUZMyNYLetophvcAN_gQ,11968
115
+ pytgcalls/types/stream/record_stream.py,sha256=f4VQ6MY8HtOxt7vz0hWBFmbbAIvTRHpAIU2nmj0TF6Y,3197
115
116
  pytgcalls/types/stream/stream_ended.py,sha256=xR_kZwFf03hA6rw_nvI7Be7GwoCKzQf_1MKaGpPDXqY,716
116
117
  pytgcalls/types/stream/stream_frames.py,sha256=028ZhNV-mN3BGqMlmxusAV1xDQpXRYCeM0WXBZhRUhA,446
117
- pytgcalls/types/stream/video_quality.py,sha256=HBfWq005kh-D19MaVE9VzVdnODzrXf4IJUimCfslfiU,231
118
- py_tgcalls-2.1.2b2.dist-info/METADATA,sha256=GxtcdfoQ7YJZWo5rwwvc1IDUdK4dR7teugIeXM80NLQ,5284
119
- py_tgcalls-2.1.2b2.dist-info/WHEEL,sha256=wXxTzcEDnjrTwFYjLPcsW_7_XihufBwmpiBeiXNBGEA,91
120
- py_tgcalls-2.1.2b2.dist-info/top_level.txt,sha256=IUDUwn0KkcbUYZbCe9R5AUb2Ob-lmllNUGQqyeXXd8A,10
121
- py_tgcalls-2.1.2b2.dist-info/RECORD,,
118
+ pytgcalls/types/stream/video_quality.py,sha256=eMCBFPwh5meX3UVEaozcGlwmgaujfpiTa3vBVSBBP_8,275
119
+ py_tgcalls-2.2.0.dist-info/METADATA,sha256=OLWKAf_6F7CxLaWYFyNr0A88kPEhdIRKi2uhTkUii38,5280
120
+ py_tgcalls-2.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
121
+ py_tgcalls-2.2.0.dist-info/top_level.txt,sha256=IUDUwn0KkcbUYZbCe9R5AUb2Ob-lmllNUGQqyeXXd8A,10
122
+ py_tgcalls-2.2.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.1.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
pytgcalls/__version__.py CHANGED
@@ -1 +1 @@
1
- __version__ = '2.1.2b2'
1
+ __version__ = '2.2.0'
pytgcalls/ffmpeg.py CHANGED
@@ -207,12 +207,12 @@ def build_command(
207
207
  if headers is not None:
208
208
  for i in headers:
209
209
  ffmpeg_command.append('-headers')
210
- ffmpeg_command.append(f'"{i}: {headers[i]}"')
210
+ ffmpeg_command.append(f'{i}: {headers[i]}')
211
211
 
212
212
  ffmpeg_command += [
213
213
  '-nostdin',
214
214
  '-i',
215
- f'"{path}"' if name == 'ffmpeg' else path,
215
+ f'{path}' if name == 'ffmpeg' else path,
216
216
  ]
217
217
  ffmpeg_command += command['mid']
218
218
 
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
 
@@ -0,0 +1,11 @@
1
+ import platform
2
+ import shlex
3
+ import subprocess
4
+ from typing import List
5
+
6
+
7
+ def list_to_cmd(args: List[str]) -> str:
8
+ if platform.system() == 'Windows':
9
+ return subprocess.list2cmdline(args)
10
+ else:
11
+ return shlex.join(args)
@@ -17,6 +17,7 @@ class LeaveCall(Scaffold):
17
17
  async def leave_call(
18
18
  self,
19
19
  chat_id: Union[int, str],
20
+ close: bool = False,
20
21
  ):
21
22
  chat_id = await self.resolve_chat_id(chat_id)
22
23
  is_p2p_waiting = (
@@ -48,3 +49,6 @@ class LeaveCall(Scaffold):
48
49
  self._need_unmute.discard(chat_id)
49
50
  self._presentations.discard(chat_id)
50
51
  self._call_sources.pop(chat_id, None)
52
+
53
+ if chat_id < 0 and close: # type: ignore
54
+ self._app.close_voice_chat(chat_id)
@@ -5,6 +5,7 @@ from typing import Union
5
5
  from ntgcalls import ConnectionMode
6
6
  from ntgcalls import ConnectionNotFound
7
7
  from ntgcalls import MediaDescription
8
+ from ntgcalls import StreamMode
8
9
  from ntgcalls import TelegramServerError
9
10
 
10
11
  from ...exceptions import TimedOutAnswer
@@ -31,8 +32,12 @@ class ConnectCall(Scaffold):
31
32
  if not payload:
32
33
  payload = await self._binding.create_call(
33
34
  chat_id,
34
- media_description,
35
35
  )
36
+ await self._binding.set_stream_sources(
37
+ chat_id,
38
+ StreamMode.CAPTURE,
39
+ media_description,
40
+ )
36
41
  result_params = await self._app.join_group_call(
37
42
  chat_id,
38
43
  payload,
@@ -63,6 +68,10 @@ class ConnectCall(Scaffold):
63
68
  )
64
69
  await self._binding.create_p2p_call(
65
70
  chat_id,
71
+ )
72
+ await self._binding.set_stream_sources(
73
+ chat_id,
74
+ StreamMode.CAPTURE,
66
75
  media_description,
67
76
  )
68
77
  data.g_a_or_b = await self._binding.init_exchange(
@@ -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:
@@ -141,19 +141,12 @@ class HandleMTProtoUpdates(Scaffold):
141
141
  chat_peer,
142
142
  ) == participant.user_id if chat_peer else False
143
143
  if is_self:
144
- if action == GroupCallParticipant.Action.LEFT:
145
- if await self._clear_call(chat_id):
146
- await self._propagate(
147
- ChatUpdate(
148
- chat_id,
149
- ChatUpdate.Status.KICKED,
150
- ),
151
- self,
152
- )
144
+ if action == GroupCallParticipant.Action.KICKED:
145
+ await self._clear_call(chat_id)
153
146
  if (
154
- chat_id in self._need_unmute and
155
- action == GroupCallParticipant.Action.UPDATED and
156
- not participant.muted_by_admin
147
+ chat_id in self._need_unmute and
148
+ action == GroupCallParticipant.Action.UPDATED
149
+ and not participant.muted_by_admin
157
150
  ):
158
151
  await self._update_status(
159
152
  chat_id,
@@ -162,8 +155,8 @@ class HandleMTProtoUpdates(Scaffold):
162
155
  await self._switch_connection(chat_id)
163
156
 
164
157
  if (
165
- participant.muted_by_admin and
166
- action != GroupCallParticipant.Action.LEFT
158
+ participant.muted_by_admin and
159
+ action != GroupCallParticipant.Action.LEFT
167
160
  ):
168
161
  self._need_unmute.add(chat_id)
169
162
  else:
@@ -44,11 +44,12 @@ class Play(Scaffold):
44
44
 
45
45
  if chat_id in await self._binding.calls():
46
46
  try:
47
- return await self._binding.set_stream_sources(
47
+ await self._binding.set_stream_sources(
48
48
  chat_id,
49
49
  StreamMode.CAPTURE,
50
50
  media_description,
51
51
  )
52
+ return
52
53
  except FileError as e:
53
54
  raise FileNotFoundError(e)
54
55
 
@@ -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
@@ -10,6 +11,7 @@ from ntgcalls import SsrcGroup
10
11
 
11
12
  from ..handlers import HandlersHolder
12
13
  from ..types import GroupCallParticipant
14
+ from ..types import UpdatedGroupCallParticipant
13
15
 
14
16
 
15
17
  class BridgedClient(HandlersHolder):
@@ -95,6 +97,12 @@ class BridgedClient(HandlersHolder):
95
97
  ):
96
98
  pass
97
99
 
100
+ async def close_voice_chat(
101
+ self,
102
+ chat_id: int,
103
+ ):
104
+ pass
105
+
98
106
  async def get_group_call_participants(
99
107
  self,
100
108
  chat_id: int,
@@ -189,13 +197,56 @@ class BridgedClient(HandlersHolder):
189
197
  bool(participant.raise_hand_rating),
190
198
  participant.volume // 100
191
199
  if participant.volume is not None else 100,
192
- bool(participant.just_joined),
193
- bool(participant.left),
194
200
  participant.source,
195
201
  BridgedClient.parse_source(participant.video),
196
202
  BridgedClient.parse_source(participant.presentation),
197
203
  )
198
204
 
205
+ @staticmethod
206
+ async def diff_participants_update(
207
+ cache,
208
+ chat_id: Optional[int],
209
+ participant,
210
+ ) -> List[UpdatedGroupCallParticipant]:
211
+ if chat_id is None:
212
+ return []
213
+ user_id = BridgedClient.chat_id(participant.peer)
214
+ participants = await cache.get_participant_list(
215
+ chat_id,
216
+ True,
217
+ )
218
+ updates = []
219
+ for p in participants:
220
+ if p.user_id == user_id:
221
+ if p.source != participant.source:
222
+ updates.append(
223
+ UpdatedGroupCallParticipant(
224
+ chat_id,
225
+ GroupCallParticipant.Action.KICKED,
226
+ p,
227
+ ),
228
+ )
229
+ participant.just_joined = True
230
+ break
231
+
232
+ updates.append(
233
+ UpdatedGroupCallParticipant(
234
+ chat_id,
235
+ BridgedClient.parse_participant_action(participant),
236
+ BridgedClient.parse_participant(participant),
237
+ ),
238
+ )
239
+ return updates
240
+
241
+ @staticmethod
242
+ def parse_participant_action(participant):
243
+ if participant.just_joined:
244
+ return GroupCallParticipant.Action.JOINED
245
+ elif participant.left:
246
+ return GroupCallParticipant.Action.LEFT
247
+ else:
248
+ return GroupCallParticipant.Action.UPDATED
249
+
199
250
  @staticmethod
200
251
  def chat_id(input_peer) -> int:
201
252
  class_name = input_peer.__class__.__name__
@@ -260,6 +311,17 @@ class BridgedClient(HandlersHolder):
260
311
  else:
261
312
  return None
262
313
 
314
+ @staticmethod
315
+ def extract_dc(error: str) -> Optional[int]:
316
+ dc_id = re.findall(
317
+ r'('
318
+ r'CALL_MIGRATE_|'
319
+ r'The file to be accessed is currently stored in DC *'
320
+ r')([0-9])',
321
+ error,
322
+ )
323
+ return int(dc_id[0][1]) if dc_id else None
324
+
263
325
  @staticmethod
264
326
  def rnd_id() -> int:
265
327
  return random.randint(0, 0x7FFFFFFF - 1)
@@ -1,5 +1,4 @@
1
1
  import logging
2
- from time import time
3
2
  from typing import Any
4
3
  from typing import List
5
4
  from typing import Optional
@@ -19,10 +18,12 @@ class ClientCache:
19
18
  app: BridgedClient,
20
19
  ):
21
20
  self._app: BridgedClient = app
22
- self._cache_duration = 1 if app.no_updates() else cache_duration
23
- self._full_chat_cache = Cache()
24
- self._call_participants_cache = Cache()
25
- self._phone_calls = Cache()
21
+ cache_duration = 0 if app.no_updates() else cache_duration
22
+ full_chat_duration = 1 if app.no_updates() else cache_duration
23
+ self._full_chat_cache = Cache(full_chat_duration)
24
+ self._call_participants_cache = Cache(cache_duration)
25
+ self._dc_call_cache = Cache(full_chat_duration)
26
+ self._phone_calls = Cache(full_chat_duration)
26
27
 
27
28
  async def get_full_chat(
28
29
  self,
@@ -45,88 +46,64 @@ class ClientCache:
45
46
  pass
46
47
  return None
47
48
 
48
- def set_participants_cache_call(
49
+ def set_participants_cache(
49
50
  self,
50
- input_id: int,
51
- participant: GroupCallParticipant,
52
- ) -> Optional[GroupCallParticipant]:
53
- chat_id = self.get_chat_id(input_id)
54
- if chat_id is not None:
55
- return self._internal_set_participants_cache(
56
- chat_id,
57
- participant,
58
- )
59
- return None
60
-
61
- def set_participants_cache_chat(
62
- self,
63
- chat_id: int,
51
+ chat_id: Optional[int],
64
52
  call_id: int,
53
+ action: GroupCallParticipant.Action,
65
54
  participant: GroupCallParticipant,
66
55
  ) -> Optional[GroupCallParticipant]:
67
- if self._call_participants_cache.get(chat_id) is None:
68
- self._call_participants_cache.put(
56
+ if chat_id is not None:
57
+ if self._call_participants_cache.get(chat_id) is None:
58
+ self._call_participants_cache.put(
59
+ chat_id,
60
+ ParticipantList(
61
+ call_id,
62
+ ),
63
+ )
64
+ participants: Optional[
65
+ ParticipantList
66
+ ] = self._call_participants_cache.get(
69
67
  chat_id,
70
- ParticipantList(
71
- call_id,
72
- ),
73
- )
74
- return self._internal_set_participants_cache(
75
- chat_id,
76
- participant,
77
- )
78
-
79
- def _internal_set_participants_cache(
80
- self,
81
- chat_id: int,
82
- participant: GroupCallParticipant,
83
- ) -> Optional[GroupCallParticipant]:
84
- participants: Optional[
85
- ParticipantList
86
- ] = self._call_participants_cache.get(
87
- chat_id,
88
- )
89
- if participants is not None:
90
- participants.last_mtproto_update = (
91
- int(time()) + self._cache_duration
92
68
  )
93
- return participants.update_participant(participant)
69
+ if participants is not None:
70
+ self._call_participants_cache.update_cache(chat_id)
71
+ return participants.update_participant(
72
+ action,
73
+ participant,
74
+ )
94
75
  return None
95
76
 
96
77
  async def get_participant_list(
97
78
  self,
98
79
  chat_id: int,
99
- ) -> Optional[List[GroupCallParticipant]]:
80
+ only_cached: bool = False,
81
+ ) -> List[GroupCallParticipant]:
100
82
  input_call = await self.get_full_chat(
101
83
  chat_id,
102
84
  )
103
85
  if input_call is not None:
104
- participants: Optional[
105
- ParticipantList
106
- ] = self._call_participants_cache.get(
107
- chat_id,
108
- )
109
- if participants is not None:
110
- last_update = participants.last_mtproto_update
111
- curr_time = int(time())
112
- if not (last_update - curr_time > 0):
113
- py_logger.debug(
114
- 'GetParticipant cache miss for %d', chat_id,
86
+ if self._call_participants_cache.get(chat_id) is None:
87
+ if only_cached:
88
+ return []
89
+ py_logger.debug(
90
+ 'GetParticipant cache miss for %d', chat_id,
91
+ )
92
+ list_participants = await self._app.get_participants(
93
+ input_call,
94
+ )
95
+ for participant in list_participants:
96
+ self.set_participants_cache(
97
+ chat_id,
98
+ input_call.id,
99
+ GroupCallParticipant.Action.UPDATED,
100
+ participant,
115
101
  )
116
- try:
117
- list_participants = await self._app.get_participants(
118
- input_call,
119
- )
120
- for participant in list_participants:
121
- self.set_participants_cache_call(
122
- input_call.id,
123
- participant,
124
- )
125
- except Exception as e:
126
- py_logger.error('Error for %s in %d', e, chat_id)
127
- else:
128
- py_logger.debug('GetParticipant cache hit for %d', chat_id)
129
- return participants.get_participants()
102
+ else:
103
+ py_logger.debug('GetParticipant cache hit for %d', chat_id)
104
+ return self._call_participants_cache.get(
105
+ chat_id,
106
+ ).get_participants()
130
107
  return []
131
108
 
132
109
  def get_chat_id(
@@ -148,7 +125,6 @@ class ClientCache:
148
125
  self._full_chat_cache.put(
149
126
  chat_id,
150
127
  input_call,
151
- self._cache_duration,
152
128
  )
153
129
  if self._call_participants_cache.get(chat_id) is None:
154
130
  self._call_participants_cache.put(
@@ -164,6 +140,23 @@ class ClientCache:
164
140
  ) -> None:
165
141
  self._full_chat_cache.pop(chat_id)
166
142
  self._call_participants_cache.pop(chat_id)
143
+ self._dc_call_cache.pop(chat_id)
144
+
145
+ def set_dc_call(
146
+ self,
147
+ chat_id: int,
148
+ dc_id: int,
149
+ ) -> None:
150
+ self._dc_call_cache.put(
151
+ chat_id,
152
+ dc_id,
153
+ )
154
+
155
+ def get_dc_call(
156
+ self,
157
+ chat_id: int,
158
+ ) -> Optional[int]:
159
+ return self._dc_call_cache.get(chat_id)
167
160
 
168
161
  def set_phone_call(
169
162
  self,