py-tgcalls 2.1.1__py3-none-any.whl → 2.1.2b1__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.1.1.dist-info → py_tgcalls-2.1.2b1.dist-info}/METADATA +2 -2
- {py_tgcalls-2.1.1.dist-info → py_tgcalls-2.1.2b1.dist-info}/RECORD +37 -23
- {py_tgcalls-2.1.1.dist-info → py_tgcalls-2.1.2b1.dist-info}/WHEEL +1 -1
- pytgcalls/__version__.py +1 -1
- pytgcalls/exceptions.py +0 -7
- pytgcalls/methods/__init__.py +2 -0
- pytgcalls/methods/internal/__init__.py +35 -0
- pytgcalls/methods/internal/clear_cache.py +8 -0
- pytgcalls/methods/internal/clear_call.py +20 -0
- pytgcalls/methods/internal/connect_call.py +133 -0
- pytgcalls/methods/internal/emit_sig_data.py +9 -0
- pytgcalls/methods/internal/handle_connection_changed.py +27 -0
- pytgcalls/methods/internal/handle_mtproto_updates.py +175 -0
- pytgcalls/methods/internal/handle_stream_ended.py +23 -0
- pytgcalls/methods/internal/handle_stream_frame.py +41 -0
- pytgcalls/methods/internal/join_presentation.py +58 -0
- pytgcalls/methods/internal/request_broadcast_part.py +42 -0
- pytgcalls/methods/internal/request_broadcast_timestamp.py +25 -0
- pytgcalls/methods/internal/switch_connection.py +35 -0
- pytgcalls/methods/internal/update_status.py +22 -0
- pytgcalls/methods/stream/play.py +6 -107
- pytgcalls/methods/stream/record.py +0 -6
- pytgcalls/methods/utilities/__init__.py +0 -6
- pytgcalls/methods/utilities/start.py +23 -296
- pytgcalls/mtproto/bridged_client.py +28 -7
- pytgcalls/mtproto/hydrogram_client.py +57 -0
- pytgcalls/mtproto/mtproto_client.py +33 -2
- pytgcalls/mtproto/pyrogram_client.py +61 -4
- pytgcalls/mtproto/telethon_client.py +57 -0
- pytgcalls/scaffold.py +79 -0
- pytgcalls/types/__init__.py +2 -0
- pytgcalls/types/calls/__init__.py +2 -0
- pytgcalls/types/calls/pending_connection.py +17 -0
- pytgcalls/methods/utilities/join_presentation.py +0 -50
- {py_tgcalls-2.1.1.dist-info → py_tgcalls-2.1.2b1.dist-info}/licenses/LICENSE +0 -0
- {py_tgcalls-2.1.1.dist-info → py_tgcalls-2.1.2b1.dist-info}/top_level.txt +0 -0
- /pytgcalls/methods/{utilities → internal}/log_retries.py +0 -0
- /pytgcalls/methods/{utilities → internal}/update_sources.py +0 -0
|
@@ -3,9 +3,11 @@ from typing import List
|
|
|
3
3
|
from typing import Optional
|
|
4
4
|
from typing import Union
|
|
5
5
|
|
|
6
|
+
from ntgcalls import MediaSegmentQuality
|
|
6
7
|
from ntgcalls import Protocol
|
|
7
8
|
from telethon import TelegramClient
|
|
8
9
|
from telethon.errors import ChannelPrivateError
|
|
10
|
+
from telethon.errors import FloodWaitError
|
|
9
11
|
from telethon.events import Raw
|
|
10
12
|
from telethon.tl.functions.channels import GetFullChannelRequest
|
|
11
13
|
from telethon.tl.functions.messages import GetDhConfigRequest
|
|
@@ -16,6 +18,7 @@ from telethon.tl.functions.phone import CreateGroupCallRequest
|
|
|
16
18
|
from telethon.tl.functions.phone import DiscardCallRequest
|
|
17
19
|
from telethon.tl.functions.phone import EditGroupCallParticipantRequest
|
|
18
20
|
from telethon.tl.functions.phone import GetGroupCallRequest
|
|
21
|
+
from telethon.tl.functions.phone import GetGroupCallStreamChannelsRequest
|
|
19
22
|
from telethon.tl.functions.phone import GetGroupParticipantsRequest
|
|
20
23
|
from telethon.tl.functions.phone import JoinGroupCallPresentationRequest
|
|
21
24
|
from telethon.tl.functions.phone import JoinGroupCallRequest
|
|
@@ -23,12 +26,14 @@ from telethon.tl.functions.phone import LeaveGroupCallPresentationRequest
|
|
|
23
26
|
from telethon.tl.functions.phone import LeaveGroupCallRequest
|
|
24
27
|
from telethon.tl.functions.phone import RequestCallRequest
|
|
25
28
|
from telethon.tl.functions.phone import SendSignalingDataRequest
|
|
29
|
+
from telethon.tl.functions.upload import GetFileRequest
|
|
26
30
|
from telethon.tl.types import ChatForbidden
|
|
27
31
|
from telethon.tl.types import DataJSON
|
|
28
32
|
from telethon.tl.types import GroupCall
|
|
29
33
|
from telethon.tl.types import GroupCallDiscarded
|
|
30
34
|
from telethon.tl.types import InputChannel
|
|
31
35
|
from telethon.tl.types import InputGroupCall
|
|
36
|
+
from telethon.tl.types import InputGroupCallStream
|
|
32
37
|
from telethon.tl.types import InputPeerChannel
|
|
33
38
|
from telethon.tl.types import InputPhoneCall
|
|
34
39
|
from telethon.tl.types import MessageActionChatDeleteUser
|
|
@@ -604,6 +609,58 @@ class TelethonClient(BridgedClient):
|
|
|
604
609
|
),
|
|
605
610
|
)
|
|
606
611
|
|
|
612
|
+
async def download_stream(
|
|
613
|
+
self,
|
|
614
|
+
chat_id: int,
|
|
615
|
+
timestamp: int,
|
|
616
|
+
limit: int,
|
|
617
|
+
video_channel: Optional[int],
|
|
618
|
+
video_quality: MediaSegmentQuality,
|
|
619
|
+
):
|
|
620
|
+
chat_call = await self._cache.get_full_chat(chat_id)
|
|
621
|
+
if chat_call is not None:
|
|
622
|
+
try:
|
|
623
|
+
return (
|
|
624
|
+
await self._app(
|
|
625
|
+
GetFileRequest(
|
|
626
|
+
location=InputGroupCallStream(
|
|
627
|
+
call=chat_call,
|
|
628
|
+
time_ms=timestamp,
|
|
629
|
+
scale=0,
|
|
630
|
+
video_channel=video_channel,
|
|
631
|
+
video_quality=BridgedClient.parse_quality(
|
|
632
|
+
video_quality,
|
|
633
|
+
),
|
|
634
|
+
),
|
|
635
|
+
offset=0,
|
|
636
|
+
limit=limit,
|
|
637
|
+
),
|
|
638
|
+
flood_sleep_threshold=0,
|
|
639
|
+
)
|
|
640
|
+
).bytes
|
|
641
|
+
except FloodWaitError:
|
|
642
|
+
pass
|
|
643
|
+
return None
|
|
644
|
+
|
|
645
|
+
async def get_stream_timestamp(
|
|
646
|
+
self,
|
|
647
|
+
chat_id: int,
|
|
648
|
+
):
|
|
649
|
+
chat_call = await self._cache.get_full_chat(chat_id)
|
|
650
|
+
if chat_call is not None:
|
|
651
|
+
# noinspection PyBroadException
|
|
652
|
+
channels = (
|
|
653
|
+
await self._app(
|
|
654
|
+
GetGroupCallStreamChannelsRequest(
|
|
655
|
+
call=chat_call,
|
|
656
|
+
),
|
|
657
|
+
)
|
|
658
|
+
).channels
|
|
659
|
+
if len(channels) > 0:
|
|
660
|
+
return channels[0].last_timestamp_ms
|
|
661
|
+
|
|
662
|
+
return 0
|
|
663
|
+
|
|
607
664
|
async def set_call_status(
|
|
608
665
|
self,
|
|
609
666
|
chat_id: int,
|
pytgcalls/scaffold.py
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
from typing import Optional
|
|
1
3
|
from typing import Union
|
|
2
4
|
|
|
5
|
+
from ntgcalls import Frame as RawFrame
|
|
6
|
+
from ntgcalls import MediaDescription
|
|
7
|
+
from ntgcalls import MediaState
|
|
8
|
+
from ntgcalls import NetworkInfo
|
|
9
|
+
from ntgcalls import SegmentPartRequest
|
|
10
|
+
from ntgcalls import StreamDevice
|
|
11
|
+
from ntgcalls import StreamMode
|
|
12
|
+
from ntgcalls import StreamType
|
|
13
|
+
|
|
3
14
|
from .handlers import HandlersHolder
|
|
15
|
+
from .types import CallConfig
|
|
16
|
+
from .types import GroupCallConfig
|
|
17
|
+
from .types import Update
|
|
4
18
|
|
|
5
19
|
|
|
6
20
|
class Scaffold(HandlersHolder):
|
|
@@ -25,6 +39,7 @@ class Scaffold(HandlersHolder):
|
|
|
25
39
|
self._call_sources = dict()
|
|
26
40
|
self._wait_connect = dict()
|
|
27
41
|
self._presentations = set()
|
|
42
|
+
self._pending_connections = dict()
|
|
28
43
|
|
|
29
44
|
def _handle_mtproto(self):
|
|
30
45
|
pass
|
|
@@ -47,9 +62,73 @@ class Scaffold(HandlersHolder):
|
|
|
47
62
|
async def _join_presentation(self, chat_id: Union[int, str], join: bool):
|
|
48
63
|
pass
|
|
49
64
|
|
|
65
|
+
async def _clear_call(self, chat_id: int):
|
|
66
|
+
pass
|
|
67
|
+
|
|
68
|
+
async def _update_status(self, chat_id: int, state: MediaState):
|
|
69
|
+
pass
|
|
70
|
+
|
|
71
|
+
async def _switch_connection(self, chat_id: int):
|
|
72
|
+
pass
|
|
73
|
+
|
|
74
|
+
async def _handle_stream_ended(
|
|
75
|
+
self,
|
|
76
|
+
chat_id: int,
|
|
77
|
+
stream_type: StreamType,
|
|
78
|
+
device: StreamDevice,
|
|
79
|
+
):
|
|
80
|
+
pass
|
|
81
|
+
|
|
82
|
+
async def _emit_sig_data(self, chat_id: int, data: bytes):
|
|
83
|
+
pass
|
|
84
|
+
|
|
85
|
+
async def _request_broadcast_timestamp(
|
|
86
|
+
self,
|
|
87
|
+
chat_id: int,
|
|
88
|
+
):
|
|
89
|
+
pass
|
|
90
|
+
|
|
91
|
+
async def _request_broadcast_part(
|
|
92
|
+
self,
|
|
93
|
+
chat_id: int,
|
|
94
|
+
part_request: SegmentPartRequest,
|
|
95
|
+
):
|
|
96
|
+
pass
|
|
97
|
+
|
|
98
|
+
async def _handle_stream_frame(
|
|
99
|
+
self,
|
|
100
|
+
chat_id: int,
|
|
101
|
+
mode: StreamMode,
|
|
102
|
+
device: StreamDevice,
|
|
103
|
+
frames: List[RawFrame],
|
|
104
|
+
):
|
|
105
|
+
pass
|
|
106
|
+
|
|
107
|
+
async def _handle_connection_changed(
|
|
108
|
+
self,
|
|
109
|
+
chat_id: int,
|
|
110
|
+
net_state: NetworkInfo,
|
|
111
|
+
):
|
|
112
|
+
pass
|
|
113
|
+
|
|
114
|
+
async def _handle_mtproto_updates(self, update: Update):
|
|
115
|
+
pass
|
|
116
|
+
|
|
117
|
+
async def _connect_call(
|
|
118
|
+
self,
|
|
119
|
+
chat_id: int,
|
|
120
|
+
media_description: MediaDescription,
|
|
121
|
+
config: Union[CallConfig, GroupCallConfig],
|
|
122
|
+
payload: Optional[str],
|
|
123
|
+
):
|
|
124
|
+
pass
|
|
125
|
+
|
|
50
126
|
@staticmethod
|
|
51
127
|
def _log_retries(r: int):
|
|
52
128
|
pass
|
|
53
129
|
|
|
130
|
+
def _clear_cache(self, chat_id: int):
|
|
131
|
+
pass
|
|
132
|
+
|
|
54
133
|
def on_update(self, filters=None):
|
|
55
134
|
pass
|
pytgcalls/types/__init__.py
CHANGED
|
@@ -5,6 +5,7 @@ from .calls import CallConfig
|
|
|
5
5
|
from .calls import CallData
|
|
6
6
|
from .calls import CallProtocol
|
|
7
7
|
from .calls import GroupCallConfig
|
|
8
|
+
from .calls import PendingConnection
|
|
8
9
|
from .calls import RawCallUpdate
|
|
9
10
|
from .chats import ChatUpdate
|
|
10
11
|
from .chats import GroupCallParticipant
|
|
@@ -35,6 +36,7 @@ __all__ = (
|
|
|
35
36
|
'CallProtocol',
|
|
36
37
|
'CallData',
|
|
37
38
|
'RawCallUpdate',
|
|
39
|
+
'PendingConnection',
|
|
38
40
|
'GroupCallConfig',
|
|
39
41
|
'GroupCallParticipant',
|
|
40
42
|
'RecordStream',
|
|
@@ -4,6 +4,7 @@ from .call_data import CallData
|
|
|
4
4
|
from .call_protocol import CallProtocol
|
|
5
5
|
from .call_sources import CallSources
|
|
6
6
|
from .group_call_config import GroupCallConfig
|
|
7
|
+
from .pending_connection import PendingConnection
|
|
7
8
|
from .raw_call_update import RawCallUpdate
|
|
8
9
|
|
|
9
10
|
__all__ = (
|
|
@@ -13,5 +14,6 @@ __all__ = (
|
|
|
13
14
|
'CallProtocol',
|
|
14
15
|
'CallSources',
|
|
15
16
|
'GroupCallConfig',
|
|
17
|
+
'PendingConnection',
|
|
16
18
|
'RawCallUpdate',
|
|
17
19
|
)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from ntgcalls import MediaDescription
|
|
2
|
+
|
|
3
|
+
from .group_call_config import GroupCallConfig
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class PendingConnection:
|
|
7
|
+
def __init__(
|
|
8
|
+
self,
|
|
9
|
+
media_description: MediaDescription,
|
|
10
|
+
config: GroupCallConfig,
|
|
11
|
+
payload: str,
|
|
12
|
+
presentation: bool,
|
|
13
|
+
):
|
|
14
|
+
self.media_description = media_description
|
|
15
|
+
self.config = config
|
|
16
|
+
self.payload = payload
|
|
17
|
+
self.presentation = presentation
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
from typing import Union
|
|
2
|
-
|
|
3
|
-
from ntgcalls import ConnectionError
|
|
4
|
-
from ntgcalls import TelegramServerError
|
|
5
|
-
|
|
6
|
-
from ...scaffold import Scaffold
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class JoinPresentation(Scaffold):
|
|
10
|
-
async def _join_presentation(
|
|
11
|
-
self,
|
|
12
|
-
chat_id: Union[int, str],
|
|
13
|
-
join: bool,
|
|
14
|
-
):
|
|
15
|
-
if join:
|
|
16
|
-
if chat_id in self._presentations:
|
|
17
|
-
return
|
|
18
|
-
for retries in range(4):
|
|
19
|
-
try:
|
|
20
|
-
self._wait_connect[
|
|
21
|
-
chat_id
|
|
22
|
-
] = self.loop.create_future()
|
|
23
|
-
payload = await self._binding.init_presentation(
|
|
24
|
-
chat_id,
|
|
25
|
-
)
|
|
26
|
-
result_params = await self._app.join_presentation(
|
|
27
|
-
chat_id,
|
|
28
|
-
payload,
|
|
29
|
-
)
|
|
30
|
-
await self._binding.connect(
|
|
31
|
-
chat_id,
|
|
32
|
-
result_params,
|
|
33
|
-
True,
|
|
34
|
-
)
|
|
35
|
-
await self._wait_connect[chat_id]
|
|
36
|
-
self._presentations.add(chat_id)
|
|
37
|
-
break
|
|
38
|
-
except TelegramServerError:
|
|
39
|
-
if retries == 3:
|
|
40
|
-
raise
|
|
41
|
-
self._log_retries(retries)
|
|
42
|
-
finally:
|
|
43
|
-
self._wait_connect.pop(chat_id, None)
|
|
44
|
-
elif chat_id in self._presentations:
|
|
45
|
-
try:
|
|
46
|
-
await self._binding.stop_presentation(chat_id)
|
|
47
|
-
await self._app.leave_presentation(chat_id)
|
|
48
|
-
except ConnectionError:
|
|
49
|
-
pass
|
|
50
|
-
self._presentations.discard(chat_id)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|