py-tgcalls 2.2.3__py3-none-any.whl → 2.2.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {py_tgcalls-2.2.3.dist-info → py_tgcalls-2.2.5.dist-info}/METADATA +2 -2
- {py_tgcalls-2.2.3.dist-info → py_tgcalls-2.2.5.dist-info}/RECORD +14 -13
- pytgcalls/__version__.py +1 -1
- pytgcalls/chat_lock.py +25 -0
- pytgcalls/methods/internal/clear_call.py +2 -1
- pytgcalls/methods/internal/connect_call.py +1 -0
- pytgcalls/methods/internal/handle_mtproto_updates.py +60 -57
- pytgcalls/mutex.py +2 -13
- pytgcalls/pytgcalls.py +2 -4
- pytgcalls/scaffold.py +1 -0
- pytgcalls/wait_counter_lock.py +5 -1
- {py_tgcalls-2.2.3.dist-info → py_tgcalls-2.2.5.dist-info}/WHEEL +0 -0
- {py_tgcalls-2.2.3.dist-info → py_tgcalls-2.2.5.dist-info}/licenses/LICENSE +0 -0
- {py_tgcalls-2.2.3.dist-info → py_tgcalls-2.2.5.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.2.
|
|
3
|
+
Version: 2.2.5
|
|
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.
|
|
23
|
+
Requires-Dist: ntgcalls<3.0.0,>=2.0.5
|
|
24
24
|
Requires-Dist: deprecation
|
|
25
25
|
Provides-Extra: pyrogram
|
|
26
26
|
Requires-Dist: pyrogram>=1.2.20; extra == "pyrogram"
|
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
py_tgcalls-2.2.
|
|
1
|
+
py_tgcalls-2.2.5.dist-info/licenses/LICENSE,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
|
|
2
2
|
pytgcalls/__init__.py,sha256=qbfwN7rYwIdCegMOzdcbvwazeNjDzgmowgcqLFNqKIM,308
|
|
3
|
-
pytgcalls/__version__.py,sha256=
|
|
3
|
+
pytgcalls/__version__.py,sha256=btKTVVdL8jf2J-q4jm7Otknf3xzOoPGoGVBFald8zts,22
|
|
4
|
+
pytgcalls/chat_lock.py,sha256=u3t0G3EQ20zn89Sn5s-GWFFX9Xmu4gYWkAgzHJOk0Mc,762
|
|
4
5
|
pytgcalls/environment.py,sha256=ctCHACvG6l8SdpPewSBhOvc70kbwpv18maC0TwLvZ08,1924
|
|
5
6
|
pytgcalls/exceptions.py,sha256=Rijc-8T93WEWJxNW9jncU8_M6mYZZZcs8F2bqitEIeI,3787
|
|
6
7
|
pytgcalls/ffmpeg.py,sha256=CZvSyuztc-TGKbKI9_2G7CLITe1ITf315YPyprWu_Pg,8645
|
|
7
8
|
pytgcalls/filters.py,sha256=8Fq_gvHHdqhIk_XwMJ9wneeZOwrvBkSOKaMJ60r3bZU,6157
|
|
8
9
|
pytgcalls/list_to_cmd.py,sha256=rGJLsejbAQdDb8pctMbLnwea5NkitlfVKc3IpoGi4V4,240
|
|
9
10
|
pytgcalls/mtproto_required.py,sha256=6B-31p5qH_6oekUgypV4nK3hqPS6Nr-pA8S81wjnbaY,630
|
|
10
|
-
pytgcalls/mutex.py,sha256=
|
|
11
|
-
pytgcalls/pytgcalls.py,sha256=
|
|
11
|
+
pytgcalls/mutex.py,sha256=hs92-LcyIkt76cTWb-czuq1PyF89GSvxpmt3h1K8l3U,381
|
|
12
|
+
pytgcalls/pytgcalls.py,sha256=SZeslmHnPjCNOiC7_3imeXstM8VQwPSN3yRDn6t1v28,1512
|
|
12
13
|
pytgcalls/pytgcalls_session.py,sha256=_BGJWvf7t3mki2DhlEPjh9cypvYuSFkMSxzTsfepwUk,2719
|
|
13
|
-
pytgcalls/scaffold.py,sha256=
|
|
14
|
+
pytgcalls/scaffold.py,sha256=1qSSTZ6Y-rXyQ65saq0yXzgeE_6iaeUjN76QQtIRb4g,3193
|
|
14
15
|
pytgcalls/statictypes.py,sha256=CdlqgQNhTZ_uTE8-B8m01fJ7TlD2B42EI2QBPxDdAtA,3842
|
|
15
16
|
pytgcalls/sync.py,sha256=IsOH3TD7cxUg_-zdGt12HoS8sBlXvcGayPZAoxxKM48,3396
|
|
16
17
|
pytgcalls/version_manager.py,sha256=egeGgvb66zWlLTMuw2U-b0x8MfnRzMm1xAEVN87HF5c,296
|
|
17
|
-
pytgcalls/wait_counter_lock.py,sha256=
|
|
18
|
+
pytgcalls/wait_counter_lock.py,sha256=dA_FbmHS1wCwtGhSAEfQrA94J9OUVhPRNcaX4vK8NRA,622
|
|
18
19
|
pytgcalls/ytdlp.py,sha256=MEPkVlFdbexbgqVRMt7C1YadPIER2R-4oN03osl5vq8,2473
|
|
19
20
|
pytgcalls/custom_api/__init__.py,sha256=ZT8d0lc2YrDuw_YSFAXXHHMewoXGFZ-ANOBIAr0vGFQ,60
|
|
20
21
|
pytgcalls/custom_api/custom_api.py,sha256=Ko3aS6psrwPmOhRPxvG0fepXt4STrA0StvINSxz4Cj8,1890
|
|
@@ -35,11 +36,11 @@ pytgcalls/methods/decorators/__init__.py,sha256=TCGaEVZnHjtOwv-3PNfaCVm0kyFhJApU
|
|
|
35
36
|
pytgcalls/methods/decorators/on_update.py,sha256=ZTL4YcQk0N4Ru56a5WItUvkSN5SAqr6_RDZvXmZMIHs,316
|
|
36
37
|
pytgcalls/methods/internal/__init__.py,sha256=fcgIxUJKT6QJD30ltnOfzKsLhzTTTklD2qxKlwCvyv0,1057
|
|
37
38
|
pytgcalls/methods/internal/clear_cache.py,sha256=IbcDOGiBJbmqOnGJWkIe8c6P_Y6e0YPkui4Hg4PAZlA,334
|
|
38
|
-
pytgcalls/methods/internal/clear_call.py,sha256=
|
|
39
|
-
pytgcalls/methods/internal/connect_call.py,sha256=
|
|
39
|
+
pytgcalls/methods/internal/clear_call.py,sha256=r9v2oPGrDfplxqlfKxT95JjOijm6daIpQjisOyKDBrA,542
|
|
40
|
+
pytgcalls/methods/internal/connect_call.py,sha256=wgRtcY-YxGDFCJcLkSIqgc81DdoA9osQ_iEErqbBH7E,5770
|
|
40
41
|
pytgcalls/methods/internal/emit_sig_data.py,sha256=ucIsknhJHB-0x7lcymXvwQ647AJQ852zH2W6MdlC3ws,216
|
|
41
42
|
pytgcalls/methods/internal/handle_connection_changed.py,sha256=_1u3J6_Pjl1Gs1u_WkhG2FAUl_hxlHUiflaMkKkJDsc,866
|
|
42
|
-
pytgcalls/methods/internal/handle_mtproto_updates.py,sha256=
|
|
43
|
+
pytgcalls/methods/internal/handle_mtproto_updates.py,sha256=I8l9n4t2haN3wR3cCWqynIBsilN1XazuLC9l8aS7Rhw,7812
|
|
43
44
|
pytgcalls/methods/internal/handle_stream_ended.py,sha256=DllD1ZfGQbwVh-S0neocwnN-8lQtwwyrzWl9teSrZbY,561
|
|
44
45
|
pytgcalls/methods/internal/handle_stream_frame.py,sha256=_FA782qlOT3tUqnySm7RBpjbgfEEzt1oEBDm-iADsbQ,1145
|
|
45
46
|
pytgcalls/methods/internal/join_presentation.py,sha256=sXhmzbLWwVFi3gFl1rv0OgJsRJBrvjzRcl60N6ydNW8,2184
|
|
@@ -116,7 +117,7 @@ pytgcalls/types/stream/record_stream.py,sha256=f4VQ6MY8HtOxt7vz0hWBFmbbAIvTRHpAI
|
|
|
116
117
|
pytgcalls/types/stream/stream_ended.py,sha256=xR_kZwFf03hA6rw_nvI7Be7GwoCKzQf_1MKaGpPDXqY,716
|
|
117
118
|
pytgcalls/types/stream/stream_frames.py,sha256=028ZhNV-mN3BGqMlmxusAV1xDQpXRYCeM0WXBZhRUhA,446
|
|
118
119
|
pytgcalls/types/stream/video_quality.py,sha256=eMCBFPwh5meX3UVEaozcGlwmgaujfpiTa3vBVSBBP_8,275
|
|
119
|
-
py_tgcalls-2.2.
|
|
120
|
-
py_tgcalls-2.2.
|
|
121
|
-
py_tgcalls-2.2.
|
|
122
|
-
py_tgcalls-2.2.
|
|
120
|
+
py_tgcalls-2.2.5.dist-info/METADATA,sha256=z5H1ZrBVTaaYMqaL4L__jniTrocWWAkdUcnF-FOCEPs,5280
|
|
121
|
+
py_tgcalls-2.2.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
122
|
+
py_tgcalls-2.2.5.dist-info/top_level.txt,sha256=IUDUwn0KkcbUYZbCe9R5AUb2Ob-lmllNUGQqyeXXd8A,10
|
|
123
|
+
py_tgcalls-2.2.5.dist-info/RECORD,,
|
pytgcalls/__version__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = '2.2.
|
|
1
|
+
__version__ = '2.2.5'
|
pytgcalls/chat_lock.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from typing import Dict
|
|
3
|
+
|
|
4
|
+
from .wait_counter_lock import WaitCounterLock
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ChatLock:
|
|
8
|
+
def __init__(self):
|
|
9
|
+
self._main_lock = asyncio.Lock()
|
|
10
|
+
self._chat_lock: Dict[int, WaitCounterLock] = {}
|
|
11
|
+
|
|
12
|
+
async def _remove_callback(self, chat_id: int):
|
|
13
|
+
async with self._main_lock:
|
|
14
|
+
if not self._chat_lock[chat_id].waiters():
|
|
15
|
+
self._chat_lock.pop(chat_id, None)
|
|
16
|
+
|
|
17
|
+
async def acquire(self, chat_id: int) -> WaitCounterLock:
|
|
18
|
+
async with self._main_lock:
|
|
19
|
+
self._chat_lock[chat_id] = self._chat_lock.get(
|
|
20
|
+
chat_id,
|
|
21
|
+
) or WaitCounterLock(
|
|
22
|
+
self._remove_callback,
|
|
23
|
+
chat_id,
|
|
24
|
+
)
|
|
25
|
+
return self._chat_lock[chat_id]
|
|
@@ -6,7 +6,8 @@ from ...scaffold import Scaffold
|
|
|
6
6
|
|
|
7
7
|
class ClearCall(Scaffold):
|
|
8
8
|
async def _clear_call(self, chat_id: int):
|
|
9
|
-
if chat_id in self._wait_connect
|
|
9
|
+
if chat_id in self._wait_connect and \
|
|
10
|
+
chat_id not in self._p2p_configs:
|
|
10
11
|
self._wait_connect[chat_id].set_exception(
|
|
11
12
|
TelegramServerError(),
|
|
12
13
|
)
|
|
@@ -43,7 +43,8 @@ class HandleMTProtoUpdates(Scaffold):
|
|
|
43
43
|
),
|
|
44
44
|
)
|
|
45
45
|
if chat_id in self._wait_connect and \
|
|
46
|
-
not self._wait_connect[chat_id].done()
|
|
46
|
+
not self._wait_connect[chat_id].done() and \
|
|
47
|
+
chat_id not in self._p2p_configs:
|
|
47
48
|
if isinstance(update, ChatUpdate):
|
|
48
49
|
if update.status & ChatUpdate.Status.DISCARDED_CALL:
|
|
49
50
|
self._wait_connect[chat_id].set_exception(
|
|
@@ -79,66 +80,68 @@ class HandleMTProtoUpdates(Scaffold):
|
|
|
79
80
|
action = update.action
|
|
80
81
|
chat_peer = self._cache_user_peer.get(chat_id)
|
|
81
82
|
user_id = participant.user_id
|
|
82
|
-
if chat_id in self._call_sources:
|
|
83
|
-
call_sources = self._call_sources[chat_id]
|
|
84
|
-
was_camera = user_id in call_sources.camera
|
|
85
|
-
was_screen = user_id in call_sources.presentation
|
|
86
83
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
try:
|
|
93
|
-
await self._binding.add_incoming_video(
|
|
94
|
-
chat_id,
|
|
95
|
-
participant.video_info.endpoint,
|
|
96
|
-
participant.video_info.sources,
|
|
97
|
-
)
|
|
98
|
-
except (ConnectionNotFound, ConnectionError):
|
|
99
|
-
pass
|
|
100
|
-
elif user_id in self._call_sources[chat_id].camera:
|
|
101
|
-
try:
|
|
102
|
-
await self._binding.remove_incoming_video(
|
|
103
|
-
chat_id,
|
|
104
|
-
self._call_sources[
|
|
105
|
-
chat_id
|
|
106
|
-
].camera[user_id],
|
|
107
|
-
)
|
|
108
|
-
except (ConnectionNotFound, ConnectionError):
|
|
109
|
-
pass
|
|
110
|
-
self._call_sources[chat_id].camera.pop(
|
|
111
|
-
user_id, None,
|
|
112
|
-
)
|
|
84
|
+
async with await self._chat_lock.acquire(chat_id):
|
|
85
|
+
if chat_id in self._call_sources:
|
|
86
|
+
call_sources = self._call_sources[chat_id]
|
|
87
|
+
was_camera = user_id in call_sources.camera
|
|
88
|
+
was_screen = user_id in call_sources.presentation
|
|
113
89
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
90
|
+
if was_camera != participant.video_camera:
|
|
91
|
+
if participant.video_info:
|
|
92
|
+
self._call_sources[chat_id].camera[
|
|
93
|
+
user_id
|
|
94
|
+
] = participant.video_info.endpoint
|
|
95
|
+
try:
|
|
96
|
+
await self._binding.add_incoming_video(
|
|
97
|
+
chat_id,
|
|
98
|
+
participant.video_info.endpoint,
|
|
99
|
+
participant.video_info.sources,
|
|
100
|
+
)
|
|
101
|
+
except (ConnectionNotFound, ConnectionError):
|
|
102
|
+
pass
|
|
103
|
+
elif user_id in self._call_sources[chat_id].camera:
|
|
104
|
+
try:
|
|
105
|
+
await self._binding.remove_incoming_video(
|
|
106
|
+
chat_id,
|
|
107
|
+
self._call_sources[
|
|
108
|
+
chat_id
|
|
109
|
+
].camera[user_id],
|
|
110
|
+
)
|
|
111
|
+
except (ConnectionNotFound, ConnectionError):
|
|
112
|
+
pass
|
|
113
|
+
self._call_sources[chat_id].camera.pop(
|
|
114
|
+
user_id, None,
|
|
124
115
|
)
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
116
|
+
|
|
117
|
+
if was_screen != participant.screen_sharing:
|
|
118
|
+
if participant.presentation_info:
|
|
119
|
+
self._call_sources[chat_id].presentation[
|
|
120
|
+
user_id
|
|
121
|
+
] = participant.presentation_info.endpoint
|
|
122
|
+
try:
|
|
123
|
+
await self._binding.add_incoming_video(
|
|
124
|
+
chat_id,
|
|
125
|
+
participant.presentation_info.endpoint,
|
|
126
|
+
participant.presentation_info.sources,
|
|
127
|
+
)
|
|
128
|
+
except (ConnectionNotFound, ConnectionError):
|
|
129
|
+
pass
|
|
130
|
+
elif user_id in self._call_sources[
|
|
131
|
+
chat_id
|
|
132
|
+
].presentation:
|
|
133
|
+
try:
|
|
134
|
+
await self._binding.remove_incoming_video(
|
|
135
|
+
chat_id,
|
|
136
|
+
self._call_sources[
|
|
137
|
+
chat_id
|
|
138
|
+
].presentation[user_id],
|
|
139
|
+
)
|
|
140
|
+
except (ConnectionNotFound, ConnectionError):
|
|
141
|
+
pass
|
|
142
|
+
self._call_sources[chat_id].presentation.pop(
|
|
143
|
+
user_id, None,
|
|
136
144
|
)
|
|
137
|
-
except (ConnectionNotFound, ConnectionError):
|
|
138
|
-
pass
|
|
139
|
-
self._call_sources[chat_id].presentation.pop(
|
|
140
|
-
user_id, None,
|
|
141
|
-
)
|
|
142
145
|
|
|
143
146
|
if chat_peer:
|
|
144
147
|
is_self = BridgedClient.chat_id(
|
pytgcalls/mutex.py
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
from functools import wraps
|
|
2
2
|
|
|
3
|
-
from .wait_counter_lock import WaitCounterLock
|
|
4
|
-
|
|
5
3
|
|
|
6
4
|
def mutex(func):
|
|
7
5
|
@wraps(func)
|
|
@@ -10,15 +8,6 @@ def mutex(func):
|
|
|
10
8
|
chat_id = await self.resolve_chat_id(
|
|
11
9
|
args[1] if len(args) > 1 else kwargs['chat_id'],
|
|
12
10
|
)
|
|
13
|
-
async with self.
|
|
14
|
-
|
|
15
|
-
chat_id,
|
|
16
|
-
) or WaitCounterLock()
|
|
17
|
-
async with self._calls_lock[chat_id]:
|
|
18
|
-
result = await func(*args, **kwargs)
|
|
19
|
-
|
|
20
|
-
async with self._lock:
|
|
21
|
-
if not self._calls_lock[chat_id].waiters():
|
|
22
|
-
self._calls_lock.pop(chat_id, None)
|
|
23
|
-
return result
|
|
11
|
+
async with await self._chat_lock.acquire(chat_id):
|
|
12
|
+
return await func(*args, **kwargs)
|
|
24
13
|
return async_wrapper
|
pytgcalls/pytgcalls.py
CHANGED
|
@@ -2,17 +2,16 @@ import asyncio
|
|
|
2
2
|
import os
|
|
3
3
|
from concurrent.futures import ThreadPoolExecutor
|
|
4
4
|
from typing import Any
|
|
5
|
-
from typing import Dict
|
|
6
5
|
|
|
7
6
|
from ntgcalls import NTgCalls
|
|
8
7
|
|
|
8
|
+
from .chat_lock import ChatLock
|
|
9
9
|
from .environment import Environment
|
|
10
10
|
from .methods import Methods
|
|
11
11
|
from .mtproto import MtProtoClient
|
|
12
12
|
from .scaffold import Scaffold
|
|
13
13
|
from .statictypes import statictypes
|
|
14
14
|
from .types import Cache
|
|
15
|
-
from .wait_counter_lock import WaitCounterLock
|
|
16
15
|
|
|
17
16
|
|
|
18
17
|
class PyTgCalls(Methods, Scaffold):
|
|
@@ -43,8 +42,7 @@ class PyTgCalls(Methods, Scaffold):
|
|
|
43
42
|
self._binding = NTgCalls()
|
|
44
43
|
self.loop = asyncio.get_event_loop()
|
|
45
44
|
self.workers = workers
|
|
46
|
-
self.
|
|
47
|
-
self._calls_lock: Dict[str, WaitCounterLock] = {}
|
|
45
|
+
self._chat_lock = ChatLock()
|
|
48
46
|
self.executor = ThreadPoolExecutor(
|
|
49
47
|
self.workers,
|
|
50
48
|
thread_name_prefix='Handler',
|
pytgcalls/scaffold.py
CHANGED
pytgcalls/wait_counter_lock.py
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
+
from typing import Callable
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
class WaitCounterLock:
|
|
5
|
-
def __init__(self):
|
|
6
|
+
def __init__(self, remove_callback: Callable, *args):
|
|
6
7
|
self._lock = asyncio.Lock()
|
|
7
8
|
self._waiters = 0
|
|
9
|
+
self._remove_callback = remove_callback
|
|
10
|
+
self._args = args
|
|
8
11
|
|
|
9
12
|
def waiters(self):
|
|
10
13
|
return self._waiters
|
|
@@ -18,3 +21,4 @@ class WaitCounterLock:
|
|
|
18
21
|
async def __aexit__(self, exc_type, exc, tb):
|
|
19
22
|
if self._lock.locked():
|
|
20
23
|
self._lock.release()
|
|
24
|
+
await self._remove_callback(*self._args)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|