py-tgcalls 2.1.1__py3-none-any.whl → 2.1.2b2__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.2b2.dist-info}/METADATA +2 -2
- {py_tgcalls-2.1.1.dist-info → py_tgcalls-2.1.2b2.dist-info}/RECORD +38 -24
- {py_tgcalls-2.1.1.dist-info → py_tgcalls-2.1.2b2.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/client_cache.py +0 -1
- 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.2b2.dist-info}/licenses/LICENSE +0 -0
- {py_tgcalls-2.1.1.dist-info → py_tgcalls-2.1.2b2.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
|
@@ -5,9 +5,11 @@ from typing import Optional
|
|
|
5
5
|
from typing import Union
|
|
6
6
|
|
|
7
7
|
import pyrogram
|
|
8
|
+
from ntgcalls import MediaSegmentQuality
|
|
8
9
|
from ntgcalls import Protocol
|
|
9
10
|
from pyrogram import Client
|
|
10
11
|
from pyrogram import ContinuePropagation
|
|
12
|
+
from pyrogram.errors import FloodWait
|
|
11
13
|
from pyrogram.raw.base import InputPeer
|
|
12
14
|
from pyrogram.raw.base import InputUser
|
|
13
15
|
from pyrogram.raw.functions.channels import GetFullChannel
|
|
@@ -19,6 +21,7 @@ from pyrogram.raw.functions.phone import CreateGroupCall
|
|
|
19
21
|
from pyrogram.raw.functions.phone import DiscardCall
|
|
20
22
|
from pyrogram.raw.functions.phone import EditGroupCallParticipant
|
|
21
23
|
from pyrogram.raw.functions.phone import GetGroupCall
|
|
24
|
+
from pyrogram.raw.functions.phone import GetGroupCallStreamChannels
|
|
22
25
|
from pyrogram.raw.functions.phone import GetGroupParticipants
|
|
23
26
|
from pyrogram.raw.functions.phone import JoinGroupCall
|
|
24
27
|
from pyrogram.raw.functions.phone import JoinGroupCallPresentation
|
|
@@ -26,6 +29,7 @@ from pyrogram.raw.functions.phone import LeaveGroupCall
|
|
|
26
29
|
from pyrogram.raw.functions.phone import LeaveGroupCallPresentation
|
|
27
30
|
from pyrogram.raw.functions.phone import RequestCall
|
|
28
31
|
from pyrogram.raw.functions.phone import SendSignalingData
|
|
32
|
+
from pyrogram.raw.functions.upload import GetFile
|
|
29
33
|
from pyrogram.raw.types import Channel
|
|
30
34
|
from pyrogram.raw.types import ChannelForbidden
|
|
31
35
|
from pyrogram.raw.types import Chat
|
|
@@ -35,6 +39,7 @@ from pyrogram.raw.types import GroupCall
|
|
|
35
39
|
from pyrogram.raw.types import GroupCallDiscarded
|
|
36
40
|
from pyrogram.raw.types import InputChannel
|
|
37
41
|
from pyrogram.raw.types import InputGroupCall
|
|
42
|
+
from pyrogram.raw.types import InputGroupCallStream
|
|
38
43
|
from pyrogram.raw.types import InputPeerChannel
|
|
39
44
|
from pyrogram.raw.types import InputPhoneCall
|
|
40
45
|
from pyrogram.raw.types import MessageActionChatDeleteUser
|
|
@@ -539,8 +544,8 @@ class PyrogramClient(BridgedClient):
|
|
|
539
544
|
)
|
|
540
545
|
|
|
541
546
|
async def create_group_call(
|
|
542
|
-
|
|
543
|
-
|
|
547
|
+
self,
|
|
548
|
+
chat_id: int,
|
|
544
549
|
):
|
|
545
550
|
result: Updates = await self._app.send(
|
|
546
551
|
CreateGroupCall(
|
|
@@ -567,8 +572,8 @@ class PyrogramClient(BridgedClient):
|
|
|
567
572
|
)
|
|
568
573
|
|
|
569
574
|
async def leave_group_call(
|
|
570
|
-
|
|
571
|
-
|
|
575
|
+
self,
|
|
576
|
+
chat_id: int,
|
|
572
577
|
):
|
|
573
578
|
chat_call = await self._cache.get_full_chat(chat_id)
|
|
574
579
|
if chat_call is not None:
|
|
@@ -620,6 +625,58 @@ class PyrogramClient(BridgedClient):
|
|
|
620
625
|
),
|
|
621
626
|
)
|
|
622
627
|
|
|
628
|
+
async def download_stream(
|
|
629
|
+
self,
|
|
630
|
+
chat_id: int,
|
|
631
|
+
timestamp: int,
|
|
632
|
+
limit: int,
|
|
633
|
+
video_channel: Optional[int],
|
|
634
|
+
video_quality: MediaSegmentQuality,
|
|
635
|
+
):
|
|
636
|
+
chat_call = await self._cache.get_full_chat(chat_id)
|
|
637
|
+
if chat_call is not None:
|
|
638
|
+
try:
|
|
639
|
+
return (
|
|
640
|
+
await self._app.send(
|
|
641
|
+
GetFile(
|
|
642
|
+
location=InputGroupCallStream(
|
|
643
|
+
call=chat_call,
|
|
644
|
+
time_ms=timestamp,
|
|
645
|
+
scale=0,
|
|
646
|
+
video_channel=video_channel,
|
|
647
|
+
video_quality=BridgedClient.parse_quality(
|
|
648
|
+
video_quality,
|
|
649
|
+
),
|
|
650
|
+
),
|
|
651
|
+
offset=0,
|
|
652
|
+
limit=limit,
|
|
653
|
+
),
|
|
654
|
+
sleep_threshold=0,
|
|
655
|
+
)
|
|
656
|
+
).bytes
|
|
657
|
+
except FloodWait:
|
|
658
|
+
pass
|
|
659
|
+
return None
|
|
660
|
+
|
|
661
|
+
async def get_stream_timestamp(
|
|
662
|
+
self,
|
|
663
|
+
chat_id: int,
|
|
664
|
+
):
|
|
665
|
+
chat_call = await self._cache.get_full_chat(chat_id)
|
|
666
|
+
if chat_call is not None:
|
|
667
|
+
# noinspection PyBroadException
|
|
668
|
+
channels = (
|
|
669
|
+
await self._app.send(
|
|
670
|
+
GetGroupCallStreamChannels(
|
|
671
|
+
call=chat_call,
|
|
672
|
+
),
|
|
673
|
+
)
|
|
674
|
+
).channels
|
|
675
|
+
if len(channels) > 0:
|
|
676
|
+
return channels[0].last_timestamp_ms
|
|
677
|
+
|
|
678
|
+
return 0
|
|
679
|
+
|
|
623
680
|
async def set_call_status(
|
|
624
681
|
self,
|
|
625
682
|
chat_id: int,
|
|
@@ -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
|