py-tgcalls 2.0.0rc6__py3-none-any.whl → 2.0.2__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.0.2.dist-info/METADATA +297 -0
- {py_tgcalls-2.0.0rc6.dist-info → py_tgcalls-2.0.2.dist-info}/RECORD +36 -36
- {py_tgcalls-2.0.0rc6.dist-info → py_tgcalls-2.0.2.dist-info}/WHEEL +1 -1
- pytgcalls/__version__.py +1 -1
- pytgcalls/ffmpeg.py +6 -7
- pytgcalls/filters.py +14 -1
- pytgcalls/media_devices/media_devices.py +4 -2
- pytgcalls/methods/calls/get_participants.py +1 -1
- pytgcalls/methods/calls/leave_call.py +12 -4
- pytgcalls/methods/stream/play.py +1 -3
- pytgcalls/methods/utilities/call_holder.py +14 -11
- pytgcalls/methods/utilities/idle.py +2 -2
- pytgcalls/methods/utilities/start.py +40 -19
- pytgcalls/mtproto/client_cache.py +1 -1
- pytgcalls/mtproto/hydrogram_client.py +9 -7
- pytgcalls/mtproto/mtproto_client.py +1 -1
- pytgcalls/mtproto/pyrogram_client.py +9 -7
- pytgcalls/mtproto/telethon_client.py +9 -7
- pytgcalls/mutex.py +2 -29
- pytgcalls/pytgcalls.py +1 -0
- pytgcalls/scaffold.py +0 -1
- pytgcalls/types/__init__.py +3 -7
- pytgcalls/types/calls/call.py +1 -10
- pytgcalls/types/calls/call_data.py +5 -3
- pytgcalls/types/calls/raw_call_update.py +1 -1
- pytgcalls/types/{groups → chats}/__init__.py +0 -4
- pytgcalls/types/{groups → chats}/chat_update.py +1 -5
- pytgcalls/types/{groups → chats}/group_call_participant.py +14 -2
- pytgcalls/types/{groups → chats}/updated_group_call_participant.py +1 -1
- pytgcalls/types/dict.py +5 -0
- pytgcalls/types/flag.py +6 -0
- pytgcalls/types/participant_list.py +2 -2
- pytgcalls/types/stream/media_stream.py +1 -5
- pytgcalls/ytdlp.py +8 -1
- py_tgcalls-2.0.0rc6.dist-info/METADATA +0 -128
- pytgcalls/types/groups/joined_group_call_participant.py +0 -12
- pytgcalls/types/groups/left_group_call_participant.py +0 -12
- {py_tgcalls-2.0.0rc6.dist-info → py_tgcalls-2.0.2.dist-info}/LICENSE +0 -0
- {py_tgcalls-2.0.0rc6.dist-info → py_tgcalls-2.0.2.dist-info}/top_level.txt +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import logging
|
|
3
3
|
|
|
4
|
+
from ntgcalls import ConnectionError
|
|
4
5
|
from ntgcalls import ConnectionNotFound
|
|
5
6
|
from ntgcalls import ConnectionState
|
|
6
|
-
from ntgcalls import ConnectionError
|
|
7
7
|
from ntgcalls import MediaState
|
|
8
8
|
from ntgcalls import StreamType
|
|
9
9
|
from ntgcalls import TelegramServerError
|
|
@@ -16,6 +16,7 @@ from ...pytgcalls_session import PyTgCallsSession
|
|
|
16
16
|
from ...scaffold import Scaffold
|
|
17
17
|
from ...types import CallData
|
|
18
18
|
from ...types import ChatUpdate
|
|
19
|
+
from ...types import GroupCallParticipant
|
|
19
20
|
from ...types import RawCallUpdate
|
|
20
21
|
from ...types import StreamAudioEnded
|
|
21
22
|
from ...types import StreamVideoEnded
|
|
@@ -32,15 +33,17 @@ class Start(Scaffold):
|
|
|
32
33
|
async def update_handler(update: Update):
|
|
33
34
|
chat_id = update.chat_id
|
|
34
35
|
if update.chat_id in self._p2p_configs:
|
|
35
|
-
|
|
36
|
+
p2p_config = self._p2p_configs[chat_id]
|
|
37
|
+
if not p2p_config.wait_data.done():
|
|
36
38
|
if isinstance(update, RawCallUpdate):
|
|
37
39
|
if update.status & RawCallUpdate.Type.UPDATED_CALL:
|
|
38
|
-
|
|
40
|
+
p2p_config.wait_data.set_result(
|
|
39
41
|
update,
|
|
40
42
|
)
|
|
41
|
-
if isinstance(update, ChatUpdate)
|
|
43
|
+
if isinstance(update, ChatUpdate) and \
|
|
44
|
+
p2p_config.outgoing:
|
|
42
45
|
if update.status & ChatUpdate.Status.DISCARDED_CALL:
|
|
43
|
-
|
|
46
|
+
p2p_config.wait_data.set_exception(
|
|
44
47
|
CallDeclined(
|
|
45
48
|
chat_id,
|
|
46
49
|
),
|
|
@@ -67,27 +70,39 @@ class Start(Scaffold):
|
|
|
67
70
|
)
|
|
68
71
|
if isinstance(update, RawCallUpdate):
|
|
69
72
|
if update.status & RawCallUpdate.Type.SIGNALING_DATA:
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
try:
|
|
74
|
+
await self._binding.send_signaling(
|
|
75
|
+
update.chat_id,
|
|
76
|
+
update.signaling_data,
|
|
77
|
+
)
|
|
78
|
+
except (ConnectionNotFound, ConnectionError):
|
|
79
|
+
pass
|
|
74
80
|
if isinstance(update, ChatUpdate):
|
|
75
81
|
if update.status & ChatUpdate.Status.LEFT_CALL:
|
|
76
82
|
await clear_call(chat_id)
|
|
77
83
|
if isinstance(update, UpdatedGroupCallParticipant):
|
|
78
84
|
participant = update.participant
|
|
85
|
+
action = participant.action
|
|
79
86
|
chat_peer = self._cache_user_peer.get(chat_id)
|
|
80
87
|
if chat_peer:
|
|
81
88
|
is_self = BridgedClient.chat_id(
|
|
82
89
|
chat_peer,
|
|
83
90
|
) == participant.user_id if chat_peer else False
|
|
84
91
|
if is_self:
|
|
85
|
-
if
|
|
86
|
-
await clear_call(chat_id)
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
92
|
+
if action == GroupCallParticipant.Action.LEFT:
|
|
93
|
+
if await clear_call(chat_id):
|
|
94
|
+
await self.propagate(
|
|
95
|
+
ChatUpdate(
|
|
96
|
+
chat_id,
|
|
97
|
+
ChatUpdate.Status.KICKED,
|
|
98
|
+
),
|
|
99
|
+
self,
|
|
100
|
+
)
|
|
101
|
+
if (
|
|
102
|
+
chat_id in self._need_unmute and
|
|
103
|
+
action == GroupCallParticipant.Action.UPDATED and
|
|
104
|
+
not participant.muted_by_admin
|
|
105
|
+
):
|
|
91
106
|
try:
|
|
92
107
|
await update_status(
|
|
93
108
|
chat_id,
|
|
@@ -96,7 +111,10 @@ class Start(Scaffold):
|
|
|
96
111
|
except ConnectionNotFound:
|
|
97
112
|
pass
|
|
98
113
|
|
|
99
|
-
if
|
|
114
|
+
if (
|
|
115
|
+
participant.muted_by_admin and
|
|
116
|
+
action != GroupCallParticipant.Action.LEFT
|
|
117
|
+
):
|
|
100
118
|
self._need_unmute.add(chat_id)
|
|
101
119
|
else:
|
|
102
120
|
self._need_unmute.discard(chat_id)
|
|
@@ -106,12 +124,15 @@ class Start(Scaffold):
|
|
|
106
124
|
self,
|
|
107
125
|
)
|
|
108
126
|
|
|
109
|
-
async def clear_call(chat_id):
|
|
127
|
+
async def clear_call(chat_id) -> bool:
|
|
128
|
+
res = False
|
|
110
129
|
try:
|
|
111
130
|
await self._binding.stop(chat_id)
|
|
131
|
+
res = True
|
|
112
132
|
except ConnectionNotFound:
|
|
113
133
|
pass
|
|
114
134
|
await clear_cache(chat_id)
|
|
135
|
+
return res
|
|
115
136
|
|
|
116
137
|
async def update_status(chat_id: int, state: MediaState):
|
|
117
138
|
try:
|
|
@@ -155,12 +176,12 @@ class Start(Scaffold):
|
|
|
155
176
|
self._wait_connect[chat_id].set_exception(
|
|
156
177
|
TelegramServerError(),
|
|
157
178
|
)
|
|
158
|
-
await
|
|
179
|
+
await clear_cache(chat_id)
|
|
159
180
|
|
|
160
181
|
if state != ConnectionState.CONNECTED:
|
|
161
182
|
if chat_id > 0:
|
|
162
183
|
await self._app.discard_call(chat_id)
|
|
163
|
-
await
|
|
184
|
+
await clear_cache(chat_id)
|
|
164
185
|
|
|
165
186
|
async def clear_cache(chat_id: int):
|
|
166
187
|
self._p2p_configs.pop(chat_id, None)
|
|
@@ -5,7 +5,7 @@ from typing import List
|
|
|
5
5
|
from typing import Optional
|
|
6
6
|
|
|
7
7
|
from ..types import Cache
|
|
8
|
-
from ..types.
|
|
8
|
+
from ..types.chats import GroupCallParticipant
|
|
9
9
|
from ..types.participant_list import ParticipantList
|
|
10
10
|
from .bridged_client import BridgedClient
|
|
11
11
|
|
|
@@ -84,13 +84,15 @@ class HydrogramClient(BridgedClient):
|
|
|
84
84
|
update,
|
|
85
85
|
UpdatePhoneCallSignalingData,
|
|
86
86
|
):
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
RawCallUpdate
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
87
|
+
user_id = self._cache.get_user_id(update.phone_call_id)
|
|
88
|
+
if user_id is not None:
|
|
89
|
+
await self.propagate(
|
|
90
|
+
RawCallUpdate(
|
|
91
|
+
user_id,
|
|
92
|
+
RawCallUpdate.Type.SIGNALING_DATA,
|
|
93
|
+
signaling_data=update.data,
|
|
94
|
+
),
|
|
95
|
+
)
|
|
94
96
|
|
|
95
97
|
if isinstance(
|
|
96
98
|
update,
|
|
@@ -92,13 +92,15 @@ class PyrogramClient(BridgedClient):
|
|
|
92
92
|
update,
|
|
93
93
|
UpdatePhoneCallSignalingData,
|
|
94
94
|
):
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
RawCallUpdate
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
95
|
+
user_id = self._cache.get_user_id(update.phone_call_id)
|
|
96
|
+
if user_id is not None:
|
|
97
|
+
await self.propagate(
|
|
98
|
+
RawCallUpdate(
|
|
99
|
+
user_id,
|
|
100
|
+
RawCallUpdate.Type.SIGNALING_DATA,
|
|
101
|
+
signaling_data=update.data,
|
|
102
|
+
),
|
|
103
|
+
)
|
|
102
104
|
|
|
103
105
|
if isinstance(
|
|
104
106
|
update,
|
|
@@ -82,13 +82,15 @@ class TelethonClient(BridgedClient):
|
|
|
82
82
|
update,
|
|
83
83
|
UpdatePhoneCallSignalingData,
|
|
84
84
|
):
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
RawCallUpdate
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
85
|
+
user_id = self._cache.get_user_id(update.phone_call_id)
|
|
86
|
+
if user_id is not None:
|
|
87
|
+
await self.propagate(
|
|
88
|
+
RawCallUpdate(
|
|
89
|
+
user_id,
|
|
90
|
+
RawCallUpdate.Type.SIGNALING_DATA,
|
|
91
|
+
signaling_data=update.data,
|
|
92
|
+
),
|
|
93
|
+
)
|
|
92
94
|
|
|
93
95
|
if isinstance(
|
|
94
96
|
update,
|
pytgcalls/mutex.py
CHANGED
|
@@ -1,37 +1,10 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
import logging
|
|
3
1
|
from functools import wraps
|
|
4
|
-
from inspect import signature
|
|
5
|
-
from typing import Optional
|
|
6
2
|
|
|
7
3
|
|
|
8
4
|
def mutex(func):
|
|
9
|
-
sig = signature(func)
|
|
10
|
-
|
|
11
5
|
@wraps(func)
|
|
12
6
|
async def async_wrapper(*args, **kwargs):
|
|
13
7
|
self = args[0]
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if 'chat_id' in bound.arguments:
|
|
17
|
-
chat_id: Optional[int] = None
|
|
18
|
-
try:
|
|
19
|
-
chat_id = await self.resolve_chat_id(
|
|
20
|
-
bound.arguments['chat_id'],
|
|
21
|
-
)
|
|
22
|
-
except Exception as e:
|
|
23
|
-
logging.debug(
|
|
24
|
-
'Error occurred while resolving chat_id. Reason: ' +
|
|
25
|
-
str(e),
|
|
26
|
-
)
|
|
27
|
-
if chat_id is not None:
|
|
28
|
-
if chat_id not in self._lock:
|
|
29
|
-
self._lock[chat_id] = asyncio.Lock()
|
|
30
|
-
async with self._lock[chat_id]:
|
|
31
|
-
try:
|
|
32
|
-
return await func(*args, **kwargs)
|
|
33
|
-
finally:
|
|
34
|
-
self._lock.pop(chat_id, None)
|
|
35
|
-
|
|
36
|
-
return await func(*args, **kwargs)
|
|
8
|
+
async with self._lock:
|
|
9
|
+
return await func(*args, **kwargs)
|
|
37
10
|
return async_wrapper
|
pytgcalls/pytgcalls.py
CHANGED
pytgcalls/scaffold.py
CHANGED
pytgcalls/types/__init__.py
CHANGED
|
@@ -6,11 +6,9 @@ from .calls import CallData
|
|
|
6
6
|
from .calls import CallProtocol
|
|
7
7
|
from .calls import GroupCallConfig
|
|
8
8
|
from .calls import RawCallUpdate
|
|
9
|
-
from .
|
|
10
|
-
from .
|
|
11
|
-
from .
|
|
12
|
-
from .groups import LeftGroupCallParticipant
|
|
13
|
-
from .groups import UpdatedGroupCallParticipant
|
|
9
|
+
from .chats import ChatUpdate
|
|
10
|
+
from .chats import GroupCallParticipant
|
|
11
|
+
from .chats import UpdatedGroupCallParticipant
|
|
14
12
|
from .stream import AudioQuality
|
|
15
13
|
from .stream import MediaStream
|
|
16
14
|
from .stream import StreamAudioEnded
|
|
@@ -30,8 +28,6 @@ __all__ = (
|
|
|
30
28
|
'RawCallUpdate',
|
|
31
29
|
'GroupCallConfig',
|
|
32
30
|
'GroupCallParticipant',
|
|
33
|
-
'JoinedGroupCallParticipant',
|
|
34
|
-
'LeftGroupCallParticipant',
|
|
35
31
|
'MediaStream',
|
|
36
32
|
'StreamAudioEnded',
|
|
37
33
|
'StreamVideoEnded',
|
pytgcalls/types/calls/call.py
CHANGED
|
@@ -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,24 +10,15 @@ 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,
|
|
28
20
|
status: Status,
|
|
29
21
|
):
|
|
30
|
-
self.chat_id: int = chat_id
|
|
31
22
|
self.call_type = Call.Type.GROUP \
|
|
32
23
|
if chat_id < 0 else Call.Type.PRIVATE
|
|
33
24
|
self.status = status
|
|
@@ -3,6 +3,8 @@ from asyncio import Future
|
|
|
3
3
|
from typing import Any
|
|
4
4
|
from typing import Optional
|
|
5
5
|
|
|
6
|
+
from ntgcalls import DhConfig
|
|
7
|
+
|
|
6
8
|
|
|
7
9
|
class CallData:
|
|
8
10
|
def __init__(
|
|
@@ -11,9 +13,9 @@ class CallData:
|
|
|
11
13
|
loop: asyncio.AbstractEventLoop,
|
|
12
14
|
g_a_hash: Optional[bytes] = None,
|
|
13
15
|
):
|
|
14
|
-
self.
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
self.dh_config = DhConfig(
|
|
17
|
+
dhc_config.g, dhc_config.p, dhc_config.random,
|
|
18
|
+
)
|
|
17
19
|
self.g_a_or_b: Optional[bytes] = g_a_hash
|
|
18
20
|
self.outgoing: bool = g_a_hash is None
|
|
19
21
|
self.wait_data: Future = loop.create_future()
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
from .chat_update import ChatUpdate
|
|
2
2
|
from .group_call_participant import GroupCallParticipant
|
|
3
|
-
from .joined_group_call_participant import JoinedGroupCallParticipant
|
|
4
|
-
from .left_group_call_participant import LeftGroupCallParticipant
|
|
5
3
|
from .updated_group_call_participant import UpdatedGroupCallParticipant
|
|
6
4
|
|
|
7
5
|
__all__ = (
|
|
8
6
|
'ChatUpdate',
|
|
9
7
|
'GroupCallParticipant',
|
|
10
|
-
'JoinedGroupCallParticipant',
|
|
11
|
-
'LeftGroupCallParticipant',
|
|
12
8
|
'UpdatedGroupCallParticipant',
|
|
13
9
|
)
|
|
@@ -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,15 @@
|
|
|
1
|
+
from enum import auto
|
|
2
|
+
|
|
1
3
|
from ...types.py_object import PyObject
|
|
4
|
+
from ..flag import Flag
|
|
2
5
|
|
|
3
6
|
|
|
4
7
|
class GroupCallParticipant(PyObject):
|
|
8
|
+
class Action(Flag):
|
|
9
|
+
JOINED = auto()
|
|
10
|
+
LEFT = auto()
|
|
11
|
+
UPDATED = auto()
|
|
12
|
+
|
|
5
13
|
def __init__(
|
|
6
14
|
self,
|
|
7
15
|
user_id: int,
|
|
@@ -23,5 +31,9 @@ class GroupCallParticipant(PyObject):
|
|
|
23
31
|
self.video_camera: bool = video_camera
|
|
24
32
|
self.raised_hand: bool = raised_hand
|
|
25
33
|
self.volume: int = volume
|
|
26
|
-
|
|
27
|
-
|
|
34
|
+
if joined:
|
|
35
|
+
self.action = self.Action.JOINED
|
|
36
|
+
elif left:
|
|
37
|
+
self.action = self.Action.LEFT
|
|
38
|
+
else:
|
|
39
|
+
self.action = self.Action.UPDATED
|
pytgcalls/types/dict.py
ADDED
pytgcalls/types/flag.py
ADDED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from typing import Dict
|
|
2
2
|
|
|
3
|
-
from ..types.
|
|
3
|
+
from ..types.chats import GroupCallParticipant
|
|
4
4
|
from ..types.list import List
|
|
5
5
|
|
|
6
6
|
|
|
@@ -17,7 +17,7 @@ class ParticipantList:
|
|
|
17
17
|
self,
|
|
18
18
|
participant: GroupCallParticipant,
|
|
19
19
|
):
|
|
20
|
-
if participant.
|
|
20
|
+
if participant.action == GroupCallParticipant.Action.LEFT:
|
|
21
21
|
if participant.user_id in self._list_participants:
|
|
22
22
|
del self._list_participants[participant.user_id]
|
|
23
23
|
else:
|
|
@@ -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,
|
pytgcalls/ytdlp.py
CHANGED
|
@@ -58,7 +58,14 @@ class YtDlp:
|
|
|
58
58
|
stdout=asyncio.subprocess.PIPE,
|
|
59
59
|
stderr=asyncio.subprocess.PIPE,
|
|
60
60
|
)
|
|
61
|
-
|
|
61
|
+
try:
|
|
62
|
+
stdout, stderr = await asyncio.wait_for(
|
|
63
|
+
proc.communicate(),
|
|
64
|
+
20,
|
|
65
|
+
)
|
|
66
|
+
except asyncio.TimeoutError:
|
|
67
|
+
proc.terminate()
|
|
68
|
+
raise YtDlpError('yt-dlp process timeout')
|
|
62
69
|
if stderr:
|
|
63
70
|
raise YtDlpError(stderr.decode())
|
|
64
71
|
data = stdout.decode().strip().split('\n')
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: py-tgcalls
|
|
3
|
-
Version: 2.0.0rc6
|
|
4
|
-
Summary: UNKNOWN
|
|
5
|
-
Home-page: https://github.com/pytgcalls/pytgcalls
|
|
6
|
-
Author: Laky-64
|
|
7
|
-
Author-email: iraci.matteo@gmail.com
|
|
8
|
-
License: LGPL-3.0
|
|
9
|
-
Platform: UNKNOWN
|
|
10
|
-
Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)
|
|
11
|
-
Classifier: Operating System :: OS Independent
|
|
12
|
-
Classifier: Programming Language :: Python :: 3
|
|
13
|
-
Classifier: Programming Language :: Python :: 3 :: Only
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
-
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
20
|
-
Requires-Python: >=3.8
|
|
21
|
-
Description-Content-Type: text/markdown
|
|
22
|
-
License-File: LICENSE
|
|
23
|
-
Requires-Dist: aiohttp (>=3.9.3)
|
|
24
|
-
Requires-Dist: deprecation
|
|
25
|
-
Requires-Dist: ntgcalls (>=1.2.0.b6)
|
|
26
|
-
Requires-Dist: psutil
|
|
27
|
-
Requires-Dist: screeninfo
|
|
28
|
-
Requires-Dist: setuptools
|
|
29
|
-
|
|
30
|
-
<img src="https://raw.githubusercontent.com/pytgcalls/pytgcalls/master/.github/images/banner.png" alt="pytgcalls logo" />
|
|
31
|
-
<p align="center">
|
|
32
|
-
<b>A simple and elegant client that allows you to make group voice calls quickly and easily.</b>
|
|
33
|
-
<br>
|
|
34
|
-
<a href="https://github.com/pytgcalls/pytgcalls/tree/master/example">
|
|
35
|
-
Examples
|
|
36
|
-
</a>
|
|
37
|
-
•
|
|
38
|
-
<a href="https://pytgcalls.github.io/">
|
|
39
|
-
Documentation
|
|
40
|
-
</a>
|
|
41
|
-
•
|
|
42
|
-
<a href="https://pypi.org/project/py-tgcalls/">
|
|
43
|
-
PyPi
|
|
44
|
-
</a>
|
|
45
|
-
•
|
|
46
|
-
<a href="https://t.me/pytgcallsnews">
|
|
47
|
-
Channel
|
|
48
|
-
</a>
|
|
49
|
-
•
|
|
50
|
-
<a href="https://t.me/pytgcallschat">
|
|
51
|
-
Chat
|
|
52
|
-
</a>
|
|
53
|
-
</p>
|
|
54
|
-
|
|
55
|
-
# PyTgCalls [](https://pypi.org/project/py-tgcalls/) [](https://pepy.tech/project/py-tgcalls)
|
|
56
|
-
This project allows making Telegram group call using MtProto and WebRTC, this is possible thanks to the power of [NTgCalls] library and [@evgeny-nadymov]
|
|
57
|
-
|
|
58
|
-
#### Example Usage
|
|
59
|
-
```python
|
|
60
|
-
from pytgcalls import PyTgCalls
|
|
61
|
-
from pytgcalls import idle
|
|
62
|
-
from pytgcalls.types import MediaStream
|
|
63
|
-
...
|
|
64
|
-
chat_id = -1001185324811
|
|
65
|
-
app = PyTgCalls(client)
|
|
66
|
-
app.start()
|
|
67
|
-
app.join_group_call(
|
|
68
|
-
chat_id,
|
|
69
|
-
MediaStream(
|
|
70
|
-
'http://docs.evostream.com/sample_content/assets/sintel1m720p.mp4',
|
|
71
|
-
)
|
|
72
|
-
)
|
|
73
|
-
idle()
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
## Features
|
|
77
|
-
- Prebuilt wheels for macOS, Linux and Windows.
|
|
78
|
-
- Supporting all type of MTProto libraries: Pyrogram, Telethon and Hydrogram.
|
|
79
|
-
- Work with voice chats in channels and chats.
|
|
80
|
-
- Join as channels or chats.
|
|
81
|
-
- Mute/unmute, pause/resume, stop/play, volume control and more...
|
|
82
|
-
|
|
83
|
-
## Requirements
|
|
84
|
-
- Python 3.7 or higher.
|
|
85
|
-
- An MTProto Client
|
|
86
|
-
- A [Telegram API key](https://docs.pyrogram.org/intro/setup#api-keys).
|
|
87
|
-
|
|
88
|
-
## How to install?
|
|
89
|
-
Here's how to install the PyTgCalls lib, the commands are given below:
|
|
90
|
-
|
|
91
|
-
``` bash
|
|
92
|
-
# With Git
|
|
93
|
-
pip install git+https://github.com/pytgcalls/pytgcalls -U
|
|
94
|
-
|
|
95
|
-
# With PyPi (Recommended)
|
|
96
|
-
pip install py-tgcalls -U
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
## Key Contributors
|
|
100
|
-
* <b><a href="https://github.com/Laky-64">@Laky-64</a> (DevOps Engineer, Software Architect):</b>
|
|
101
|
-
* Played a crucial role in developing PyTgCalls being an ex developer of pyservercall and of tgcallsjs.
|
|
102
|
-
* Automation with GitHub Actions
|
|
103
|
-
* <b><a href="https://github.com/kuogi">@kuogi</a> (Senior UI/UX designer, Documenter):</b>
|
|
104
|
-
* As a Senior UI/UX Designer, Kuogi has significantly improved the user interface of our documentation,
|
|
105
|
-
making it more visually appealing and user-friendly.
|
|
106
|
-
* Played a key role in writing and structuring our documentation, ensuring that it is clear,
|
|
107
|
-
informative, and accessible to all users.
|
|
108
|
-
* <b><a href="https://github.com/vrumger">@vrumger</a> (Senior Node.js Developer, Software Architect):</b>
|
|
109
|
-
* Has made important fixes and enhancements to the WebRTC component of the library,
|
|
110
|
-
improving its stability and performance.
|
|
111
|
-
* Main developer of TgCallsJS
|
|
112
|
-
* <b><a href="https://github.com/alemidev">@alemidev</a> (Senior Python Developer):</b>
|
|
113
|
-
* Has made important fixes and enhancements to the async part of the library
|
|
114
|
-
|
|
115
|
-
## Junior Developers
|
|
116
|
-
* <b><a href="https://github.com/TuriOG">@TuriOG</a> (Junior Python Developer):</b>
|
|
117
|
-
* Currently working on integrating NTgCalls into <a href="//github.com/pytgcalls/pytgcalls">PyTgCalls</a>, an important step
|
|
118
|
-
in expanding the functionality and usability of the library.
|
|
119
|
-
|
|
120
|
-
## Special Thanks
|
|
121
|
-
* <b><a href="https://github.com/evgeny-nadymov">@evgeny-nadymov</a>:</b>
|
|
122
|
-
A heartfelt thank you to Evgeny Nadymov for graciously allowing us to use their code from telegram-react.
|
|
123
|
-
His contribution has been pivotal to the success of this project.
|
|
124
|
-
|
|
125
|
-
[NTgCalls]: https://github.com/pytgcalls/ntgcalls
|
|
126
|
-
[@evgeny-nadymov]: https://github.com/evgeny-nadymov/
|
|
127
|
-
|
|
128
|
-
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
from ..groups import GroupCallParticipant
|
|
2
|
-
from ..update import Update
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class JoinedGroupCallParticipant(Update):
|
|
6
|
-
def __init__(
|
|
7
|
-
self,
|
|
8
|
-
chat_id: int,
|
|
9
|
-
participant: GroupCallParticipant,
|
|
10
|
-
):
|
|
11
|
-
super().__init__(chat_id)
|
|
12
|
-
self.participant = participant
|