py-tgcalls 2.1.2b3__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.
- {py_tgcalls-2.1.2b3.dist-info → py_tgcalls-2.2.0.dist-info}/METADATA +2 -2
- {py_tgcalls-2.1.2b3.dist-info → py_tgcalls-2.2.0.dist-info}/RECORD +33 -32
- {py_tgcalls-2.1.2b3.dist-info → py_tgcalls-2.2.0.dist-info}/WHEEL +1 -1
- pytgcalls/__version__.py +1 -1
- pytgcalls/exceptions.py +0 -7
- pytgcalls/ffmpeg.py +2 -2
- pytgcalls/filters.py +6 -2
- pytgcalls/list_to_cmd.py +11 -0
- pytgcalls/methods/calls/leave_call.py +4 -0
- pytgcalls/methods/internal/connect_call.py +10 -12
- pytgcalls/methods/internal/handle_mtproto_updates.py +8 -15
- pytgcalls/methods/stream/play.py +2 -1
- pytgcalls/mtproto/bridged_client.py +64 -2
- pytgcalls/mtproto/client_cache.py +65 -72
- pytgcalls/mtproto/hydrogram_client.py +132 -35
- pytgcalls/mtproto/mtproto_client.py +11 -0
- pytgcalls/mtproto/pyrogram_client.py +135 -43
- pytgcalls/mtproto/telethon_client.py +95 -35
- pytgcalls/mutex.py +3 -1
- pytgcalls/types/cache.py +10 -5
- pytgcalls/types/chats/group_call_participant.py +1 -8
- pytgcalls/types/chats/updated_group_call_participant.py +2 -0
- pytgcalls/types/dict.py +1 -1
- pytgcalls/types/flag.py +4 -3
- pytgcalls/types/list.py +1 -1
- pytgcalls/types/participant_list.py +3 -3
- pytgcalls/types/py_object.py +4 -2
- pytgcalls/types/stream/media_stream.py +5 -4
- pytgcalls/types/stream/record_stream.py +3 -1
- pytgcalls/types/stream/video_quality.py +3 -1
- pytgcalls/ytdlp.py +3 -2
- {py_tgcalls-2.1.2b3.dist-info → py_tgcalls-2.2.0.dist-info}/licenses/LICENSE +0 -0
- {py_tgcalls-2.1.2b3.dist-info → py_tgcalls-2.2.0.dist-info}/top_level.txt +0 -0
|
@@ -6,7 +6,9 @@ from typing import Union
|
|
|
6
6
|
from ntgcalls import MediaSegmentQuality
|
|
7
7
|
from ntgcalls import Protocol
|
|
8
8
|
from telethon import TelegramClient
|
|
9
|
+
from telethon.errors import BadRequestError
|
|
9
10
|
from telethon.errors import ChannelPrivateError
|
|
11
|
+
from telethon.errors import FileMigrateError
|
|
10
12
|
from telethon.errors import FloodWaitError
|
|
11
13
|
from telethon.events import Raw
|
|
12
14
|
from telethon.tl.functions.channels import GetFullChannelRequest
|
|
@@ -16,6 +18,7 @@ from telethon.tl.functions.phone import AcceptCallRequest
|
|
|
16
18
|
from telethon.tl.functions.phone import ConfirmCallRequest
|
|
17
19
|
from telethon.tl.functions.phone import CreateGroupCallRequest
|
|
18
20
|
from telethon.tl.functions.phone import DiscardCallRequest
|
|
21
|
+
from telethon.tl.functions.phone import DiscardGroupCallRequest
|
|
19
22
|
from telethon.tl.functions.phone import EditGroupCallParticipantRequest
|
|
20
23
|
from telethon.tl.functions.phone import GetGroupCallRequest
|
|
21
24
|
from telethon.tl.functions.phone import GetGroupCallStreamChannelsRequest
|
|
@@ -68,7 +71,6 @@ from ..types import CallProtocol
|
|
|
68
71
|
from ..types import ChatUpdate
|
|
69
72
|
from ..types import GroupCallParticipant
|
|
70
73
|
from ..types import RawCallUpdate
|
|
71
|
-
from ..types import UpdatedGroupCallParticipant
|
|
72
74
|
from .bridged_client import BridgedClient
|
|
73
75
|
from .client_cache import ClientCache
|
|
74
76
|
|
|
@@ -178,19 +180,22 @@ class TelethonClient(BridgedClient):
|
|
|
178
180
|
update,
|
|
179
181
|
UpdateGroupCallParticipants,
|
|
180
182
|
):
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
183
|
+
for participant in update.participants:
|
|
184
|
+
chat_id = self._cache.get_chat_id(update.call.id)
|
|
185
|
+
p_updates = await self.diff_participants_update(
|
|
186
|
+
self._cache,
|
|
187
|
+
chat_id,
|
|
188
|
+
participant,
|
|
186
189
|
)
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
190
|
+
for p_update in p_updates:
|
|
191
|
+
result = self._cache.set_participants_cache(
|
|
192
|
+
chat_id,
|
|
193
|
+
update.call.id,
|
|
194
|
+
p_update.action,
|
|
195
|
+
p_update.participant,
|
|
193
196
|
)
|
|
197
|
+
if result is not None:
|
|
198
|
+
await self._propagate(p_update)
|
|
194
199
|
if isinstance(
|
|
195
200
|
update,
|
|
196
201
|
UpdateGroupCall,
|
|
@@ -309,7 +314,7 @@ class TelethonClient(BridgedClient):
|
|
|
309
314
|
chat = await self._app.get_input_entity(chat_id)
|
|
310
315
|
if isinstance(chat, InputPeerChannel):
|
|
311
316
|
input_call = (
|
|
312
|
-
await self.
|
|
317
|
+
await self._invoke(
|
|
313
318
|
GetFullChannelRequest(
|
|
314
319
|
InputChannel(
|
|
315
320
|
chat.channel_id,
|
|
@@ -320,14 +325,14 @@ class TelethonClient(BridgedClient):
|
|
|
320
325
|
).full_chat.call
|
|
321
326
|
else:
|
|
322
327
|
input_call = (
|
|
323
|
-
await self.
|
|
328
|
+
await self._invoke(
|
|
324
329
|
GetFullChatRequest(chat_id),
|
|
325
330
|
)
|
|
326
331
|
).full_chat.call
|
|
327
332
|
|
|
328
333
|
if input_call is not None:
|
|
329
334
|
raw_call = (
|
|
330
|
-
await self.
|
|
335
|
+
await self._invoke(
|
|
331
336
|
GetGroupCallRequest(
|
|
332
337
|
call=input_call,
|
|
333
338
|
limit=-1,
|
|
@@ -337,9 +342,10 @@ class TelethonClient(BridgedClient):
|
|
|
337
342
|
call: GroupCall = raw_call.call
|
|
338
343
|
participants: List[GroupCallParticipant] = raw_call.participants
|
|
339
344
|
for participant in participants:
|
|
340
|
-
self._cache.
|
|
345
|
+
self._cache.set_participants_cache(
|
|
341
346
|
chat_id,
|
|
342
347
|
call.id,
|
|
348
|
+
self.parse_participant_action(participant),
|
|
343
349
|
self.parse_participant(participant),
|
|
344
350
|
)
|
|
345
351
|
if call.schedule_date is not None:
|
|
@@ -348,7 +354,7 @@ class TelethonClient(BridgedClient):
|
|
|
348
354
|
return input_call
|
|
349
355
|
|
|
350
356
|
async def get_dhc(self) -> DhConfig:
|
|
351
|
-
return await self.
|
|
357
|
+
return await self._invoke(
|
|
352
358
|
GetDhConfigRequest(
|
|
353
359
|
version=0,
|
|
354
360
|
random_length=256,
|
|
@@ -370,7 +376,7 @@ class TelethonClient(BridgedClient):
|
|
|
370
376
|
participants = []
|
|
371
377
|
next_offset = ''
|
|
372
378
|
while True:
|
|
373
|
-
result = await self.
|
|
379
|
+
result = await self._invoke(
|
|
374
380
|
GetGroupParticipantsRequest(
|
|
375
381
|
call=input_call,
|
|
376
382
|
ids=[],
|
|
@@ -397,7 +403,7 @@ class TelethonClient(BridgedClient):
|
|
|
397
403
|
) -> str:
|
|
398
404
|
chat_call = await self._cache.get_full_chat(chat_id)
|
|
399
405
|
if chat_call is not None:
|
|
400
|
-
result: Updates = await self.
|
|
406
|
+
result: Updates = await self._invoke(
|
|
401
407
|
JoinGroupCallRequest(
|
|
402
408
|
call=chat_call,
|
|
403
409
|
params=DataJSON(data=json_join),
|
|
@@ -414,8 +420,10 @@ class TelethonClient(BridgedClient):
|
|
|
414
420
|
):
|
|
415
421
|
participants = update.participants
|
|
416
422
|
for participant in participants:
|
|
417
|
-
self._cache.
|
|
423
|
+
self._cache.set_participants_cache(
|
|
424
|
+
chat_id,
|
|
418
425
|
update.call.id,
|
|
426
|
+
self.parse_participant_action(participant),
|
|
419
427
|
self.parse_participant(participant),
|
|
420
428
|
)
|
|
421
429
|
if isinstance(update, UpdateGroupCallConnection):
|
|
@@ -430,7 +438,7 @@ class TelethonClient(BridgedClient):
|
|
|
430
438
|
):
|
|
431
439
|
chat_call = await self._cache.get_full_chat(chat_id)
|
|
432
440
|
if chat_call is not None:
|
|
433
|
-
result: Updates = await self.
|
|
441
|
+
result: Updates = await self._invoke(
|
|
434
442
|
JoinGroupCallPresentationRequest(
|
|
435
443
|
call=chat_call,
|
|
436
444
|
params=DataJSON(data=json_join),
|
|
@@ -448,7 +456,7 @@ class TelethonClient(BridgedClient):
|
|
|
448
456
|
):
|
|
449
457
|
chat_call = await self._cache.get_full_chat(chat_id)
|
|
450
458
|
if chat_call is not None:
|
|
451
|
-
await self.
|
|
459
|
+
await self._invoke(
|
|
452
460
|
LeaveGroupCallPresentationRequest(
|
|
453
461
|
call=chat_call,
|
|
454
462
|
),
|
|
@@ -461,7 +469,7 @@ class TelethonClient(BridgedClient):
|
|
|
461
469
|
protocol: Protocol,
|
|
462
470
|
has_video: bool,
|
|
463
471
|
):
|
|
464
|
-
update = await self.
|
|
472
|
+
update = await self._invoke(
|
|
465
473
|
RequestCallRequest(
|
|
466
474
|
user_id=await self.resolve_peer(user_id),
|
|
467
475
|
random_id=self.rnd_id(),
|
|
@@ -484,7 +492,7 @@ class TelethonClient(BridgedClient):
|
|
|
484
492
|
g_b: bytes,
|
|
485
493
|
protocol: Protocol,
|
|
486
494
|
):
|
|
487
|
-
return await self.
|
|
495
|
+
return await self._invoke(
|
|
488
496
|
AcceptCallRequest(
|
|
489
497
|
peer=self._cache.get_phone_call(user_id),
|
|
490
498
|
g_b=g_b,
|
|
@@ -500,7 +508,7 @@ class TelethonClient(BridgedClient):
|
|
|
500
508
|
protocol: Protocol,
|
|
501
509
|
) -> CallProtocol:
|
|
502
510
|
res = (
|
|
503
|
-
await self.
|
|
511
|
+
await self._invoke(
|
|
504
512
|
ConfirmCallRequest(
|
|
505
513
|
peer=self._cache.get_phone_call(user_id),
|
|
506
514
|
g_a=g_a,
|
|
@@ -520,7 +528,7 @@ class TelethonClient(BridgedClient):
|
|
|
520
528
|
user_id: int,
|
|
521
529
|
data: bytes,
|
|
522
530
|
):
|
|
523
|
-
await self.
|
|
531
|
+
await self._invoke(
|
|
524
532
|
SendSignalingDataRequest(
|
|
525
533
|
peer=self._cache.get_phone_call(user_id),
|
|
526
534
|
data=data,
|
|
@@ -531,7 +539,7 @@ class TelethonClient(BridgedClient):
|
|
|
531
539
|
self,
|
|
532
540
|
chat_id: int,
|
|
533
541
|
):
|
|
534
|
-
result: Updates = await self.
|
|
542
|
+
result: Updates = await self._invoke(
|
|
535
543
|
CreateGroupCallRequest(
|
|
536
544
|
peer=await self.resolve_peer(chat_id),
|
|
537
545
|
random_id=self.rnd_id(),
|
|
@@ -561,13 +569,26 @@ class TelethonClient(BridgedClient):
|
|
|
561
569
|
):
|
|
562
570
|
chat_call = await self._cache.get_full_chat(chat_id)
|
|
563
571
|
if chat_call is not None:
|
|
564
|
-
await self.
|
|
572
|
+
await self._invoke(
|
|
565
573
|
LeaveGroupCallRequest(
|
|
566
574
|
call=chat_call,
|
|
567
575
|
source=0,
|
|
568
576
|
),
|
|
569
577
|
)
|
|
570
578
|
|
|
579
|
+
async def close_voice_chat(
|
|
580
|
+
self,
|
|
581
|
+
chat_id: int,
|
|
582
|
+
):
|
|
583
|
+
chat_call = await self._cache.get_full_chat(chat_id)
|
|
584
|
+
if chat_call is not None:
|
|
585
|
+
await self._invoke(
|
|
586
|
+
DiscardGroupCallRequest(
|
|
587
|
+
call=chat_call,
|
|
588
|
+
),
|
|
589
|
+
)
|
|
590
|
+
self._cache.drop_cache(chat_id)
|
|
591
|
+
|
|
571
592
|
async def discard_call(
|
|
572
593
|
self,
|
|
573
594
|
chat_id: int,
|
|
@@ -581,7 +602,7 @@ class TelethonClient(BridgedClient):
|
|
|
581
602
|
if is_missed
|
|
582
603
|
else PhoneCallDiscardReasonHangup()
|
|
583
604
|
)
|
|
584
|
-
await self.
|
|
605
|
+
await self._invoke(
|
|
585
606
|
DiscardCallRequest(
|
|
586
607
|
peer=peer,
|
|
587
608
|
duration=0,
|
|
@@ -600,7 +621,7 @@ class TelethonClient(BridgedClient):
|
|
|
600
621
|
):
|
|
601
622
|
chat_call = await self._cache.get_full_chat(chat_id)
|
|
602
623
|
if chat_call is not None:
|
|
603
|
-
await self.
|
|
624
|
+
await self._invoke(
|
|
604
625
|
EditGroupCallParticipantRequest(
|
|
605
626
|
call=chat_call,
|
|
606
627
|
participant=participant,
|
|
@@ -621,7 +642,7 @@ class TelethonClient(BridgedClient):
|
|
|
621
642
|
if chat_call is not None:
|
|
622
643
|
try:
|
|
623
644
|
return (
|
|
624
|
-
await self.
|
|
645
|
+
await self._invoke(
|
|
625
646
|
GetFileRequest(
|
|
626
647
|
location=InputGroupCallStream(
|
|
627
648
|
call=chat_call,
|
|
@@ -635,7 +656,8 @@ class TelethonClient(BridgedClient):
|
|
|
635
656
|
offset=0,
|
|
636
657
|
limit=limit,
|
|
637
658
|
),
|
|
638
|
-
|
|
659
|
+
chat_id=chat_id,
|
|
660
|
+
sleep_threshold=0,
|
|
639
661
|
)
|
|
640
662
|
).bytes
|
|
641
663
|
except FloodWaitError:
|
|
@@ -648,12 +670,12 @@ class TelethonClient(BridgedClient):
|
|
|
648
670
|
):
|
|
649
671
|
chat_call = await self._cache.get_full_chat(chat_id)
|
|
650
672
|
if chat_call is not None:
|
|
651
|
-
# noinspection PyBroadException
|
|
652
673
|
channels = (
|
|
653
|
-
await self.
|
|
674
|
+
await self._invoke(
|
|
654
675
|
GetGroupCallStreamChannelsRequest(
|
|
655
676
|
call=chat_call,
|
|
656
677
|
),
|
|
678
|
+
chat_id=chat_id,
|
|
657
679
|
)
|
|
658
680
|
).channels
|
|
659
681
|
if len(channels) > 0:
|
|
@@ -672,7 +694,7 @@ class TelethonClient(BridgedClient):
|
|
|
672
694
|
):
|
|
673
695
|
chat_call = await self._cache.get_full_chat(chat_id)
|
|
674
696
|
if chat_call is not None:
|
|
675
|
-
await self.
|
|
697
|
+
await self._invoke(
|
|
676
698
|
EditGroupCallParticipantRequest(
|
|
677
699
|
call=chat_call,
|
|
678
700
|
participant=participant,
|
|
@@ -711,6 +733,44 @@ class TelethonClient(BridgedClient):
|
|
|
711
733
|
def no_updates(self):
|
|
712
734
|
return False
|
|
713
735
|
|
|
736
|
+
# noinspection PyProtectedMember,PyUnresolvedReferences
|
|
737
|
+
async def _invoke(
|
|
738
|
+
self,
|
|
739
|
+
request,
|
|
740
|
+
dc_id: Optional[int] = None,
|
|
741
|
+
chat_id: Optional[int] = None,
|
|
742
|
+
sleep_threshold: Optional[int] = None,
|
|
743
|
+
):
|
|
744
|
+
try:
|
|
745
|
+
if chat_id is not None:
|
|
746
|
+
dc_id = self._cache.get_dc_call(chat_id)
|
|
747
|
+
if dc_id is None or self._app.session.dc_id == dc_id:
|
|
748
|
+
sender_dc = self._app._sender
|
|
749
|
+
else:
|
|
750
|
+
sender_dc = await self._app._borrow_exported_sender(dc_id)
|
|
751
|
+
return await self._app._call(
|
|
752
|
+
sender_dc,
|
|
753
|
+
request,
|
|
754
|
+
flood_sleep_threshold=sleep_threshold,
|
|
755
|
+
)
|
|
756
|
+
except (BadRequestError, FileMigrateError) as e:
|
|
757
|
+
dc_new = BridgedClient.extract_dc(
|
|
758
|
+
str(e),
|
|
759
|
+
)
|
|
760
|
+
if dc_new is not None:
|
|
761
|
+
if chat_id is not None:
|
|
762
|
+
self._cache.set_dc_call(
|
|
763
|
+
chat_id,
|
|
764
|
+
dc_new,
|
|
765
|
+
)
|
|
766
|
+
return await self._invoke(
|
|
767
|
+
request,
|
|
768
|
+
dc_new,
|
|
769
|
+
chat_id,
|
|
770
|
+
sleep_threshold,
|
|
771
|
+
)
|
|
772
|
+
raise
|
|
773
|
+
|
|
714
774
|
# noinspection PyUnresolvedReferences
|
|
715
775
|
async def start(self):
|
|
716
776
|
await self._app.start()
|
pytgcalls/mutex.py
CHANGED
|
@@ -7,7 +7,9 @@ def mutex(func):
|
|
|
7
7
|
@wraps(func)
|
|
8
8
|
async def async_wrapper(*args, **kwargs):
|
|
9
9
|
self = args[0]
|
|
10
|
-
chat_id = await self.resolve_chat_id(
|
|
10
|
+
chat_id = await self.resolve_chat_id(
|
|
11
|
+
args[1] if len(args) > 1 else kwargs['chat_id'],
|
|
12
|
+
)
|
|
11
13
|
async with self._lock:
|
|
12
14
|
self._calls_lock[chat_id] = self._calls_lock.get(
|
|
13
15
|
chat_id,
|
pytgcalls/types/cache.py
CHANGED
|
@@ -8,13 +8,13 @@ from typing import Optional
|
|
|
8
8
|
@dataclass
|
|
9
9
|
class CacheEntry:
|
|
10
10
|
time: int
|
|
11
|
-
expiry_time: int
|
|
12
11
|
data: Any
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
class Cache:
|
|
16
|
-
def __init__(self):
|
|
15
|
+
def __init__(self, expiry_time: int = 0):
|
|
17
16
|
self._store: Dict[int, CacheEntry] = {} # type: ignore
|
|
17
|
+
self._expiry_time = expiry_time
|
|
18
18
|
|
|
19
19
|
def get(self, chat_id: int):
|
|
20
20
|
if chat_id in self._store:
|
|
@@ -25,13 +25,18 @@ class Cache:
|
|
|
25
25
|
self._store.pop(chat_id, None)
|
|
26
26
|
return None
|
|
27
27
|
|
|
28
|
-
def put(self, chat_id: int, data: Any
|
|
28
|
+
def put(self, chat_id: int, data: Any) -> None:
|
|
29
29
|
self._store[chat_id] = CacheEntry(
|
|
30
|
-
time=0
|
|
31
|
-
|
|
30
|
+
time=0
|
|
31
|
+
if self._expiry_time == 0 else
|
|
32
|
+
(int(time()) + self._expiry_time),
|
|
32
33
|
data=data,
|
|
33
34
|
)
|
|
34
35
|
|
|
36
|
+
def update_cache(self, chat_id: int) -> None:
|
|
37
|
+
if chat_id in self._store:
|
|
38
|
+
self._store[chat_id].time = int(time()) + self._expiry_time
|
|
39
|
+
|
|
35
40
|
@property
|
|
36
41
|
def keys(self):
|
|
37
42
|
return list(self._store)
|
|
@@ -12,6 +12,7 @@ class GroupCallParticipant(PyObject):
|
|
|
12
12
|
class Action(Flag):
|
|
13
13
|
JOINED = auto()
|
|
14
14
|
LEFT = auto()
|
|
15
|
+
KICKED = auto()
|
|
15
16
|
UPDATED = auto()
|
|
16
17
|
|
|
17
18
|
class SourceInfo(PyObject):
|
|
@@ -33,8 +34,6 @@ class GroupCallParticipant(PyObject):
|
|
|
33
34
|
video_camera: bool,
|
|
34
35
|
raised_hand: bool,
|
|
35
36
|
volume: int,
|
|
36
|
-
joined: bool,
|
|
37
|
-
left: bool,
|
|
38
37
|
source: int,
|
|
39
38
|
video_info: Optional[SourceInfo],
|
|
40
39
|
presentation_info: Optional[SourceInfo],
|
|
@@ -48,12 +47,6 @@ class GroupCallParticipant(PyObject):
|
|
|
48
47
|
self.video_camera: bool = video_camera
|
|
49
48
|
self.raised_hand: bool = raised_hand
|
|
50
49
|
self.volume: int = volume
|
|
51
|
-
if joined:
|
|
52
|
-
self.action = self.Action.JOINED
|
|
53
|
-
elif left:
|
|
54
|
-
self.action = self.Action.LEFT
|
|
55
|
-
else:
|
|
56
|
-
self.action = self.Action.UPDATED
|
|
57
50
|
self.video_info: Optional[
|
|
58
51
|
GroupCallParticipant.SourceInfo
|
|
59
52
|
] = video_info
|
pytgcalls/types/dict.py
CHANGED
pytgcalls/types/flag.py
CHANGED
pytgcalls/types/list.py
CHANGED
|
@@ -10,14 +10,14 @@ class ParticipantList:
|
|
|
10
10
|
input_id: int,
|
|
11
11
|
):
|
|
12
12
|
self._list_participants: Dict[int, GroupCallParticipant] = {}
|
|
13
|
-
self.last_mtproto_update: int = 0
|
|
14
13
|
self.input_id: int = input_id
|
|
15
14
|
|
|
16
15
|
def update_participant(
|
|
17
16
|
self,
|
|
17
|
+
action: GroupCallParticipant.Action,
|
|
18
18
|
participant: GroupCallParticipant,
|
|
19
|
-
):
|
|
20
|
-
if
|
|
19
|
+
) -> GroupCallParticipant:
|
|
20
|
+
if 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:
|
pytgcalls/types/py_object.py
CHANGED
|
@@ -11,8 +11,10 @@ class PyObject:
|
|
|
11
11
|
def default(obj) -> Union[str, Dict[str, str], List[Any]]:
|
|
12
12
|
if isinstance(obj, bytes):
|
|
13
13
|
return repr(obj)
|
|
14
|
-
|
|
15
|
-
return
|
|
14
|
+
elif isinstance(obj, Enum):
|
|
15
|
+
return ' | '.join(
|
|
16
|
+
[f"{obj.__class__.__name__}.{x}" for x in obj.name.split('|')],
|
|
17
|
+
)
|
|
16
18
|
return {
|
|
17
19
|
'_': obj.__class__.__name__,
|
|
18
20
|
**{
|
|
@@ -13,6 +13,7 @@ from ...exceptions import NoAudioSourceFound
|
|
|
13
13
|
from ...exceptions import NoVideoSourceFound
|
|
14
14
|
from ...ffmpeg import build_command
|
|
15
15
|
from ...ffmpeg import check_stream
|
|
16
|
+
from ...list_to_cmd import list_to_cmd
|
|
16
17
|
from ...media_devices.input_device import InputDevice
|
|
17
18
|
from ...media_devices.screen_device import ScreenDevice
|
|
18
19
|
from ...statictypes import statictypes
|
|
@@ -145,7 +146,7 @@ class MediaStream(Stream):
|
|
|
145
146
|
if self._is_audio_external else
|
|
146
147
|
AudioStream(
|
|
147
148
|
MediaSource.SHELL,
|
|
148
|
-
|
|
149
|
+
list_to_cmd(
|
|
149
150
|
build_command(
|
|
150
151
|
'ffmpeg',
|
|
151
152
|
self._ffmpeg_parameters,
|
|
@@ -178,7 +179,7 @@ class MediaStream(Stream):
|
|
|
178
179
|
if self._is_video_external else
|
|
179
180
|
VideoStream(
|
|
180
181
|
MediaSource.SHELL,
|
|
181
|
-
|
|
182
|
+
list_to_cmd(
|
|
182
183
|
build_command(
|
|
183
184
|
'ffmpeg',
|
|
184
185
|
self._ffmpeg_parameters,
|
|
@@ -229,7 +230,7 @@ class MediaStream(Stream):
|
|
|
229
230
|
]
|
|
230
231
|
except LiveStreamFound:
|
|
231
232
|
live_stream = True
|
|
232
|
-
self.camera.path =
|
|
233
|
+
self.camera.path = list_to_cmd(
|
|
233
234
|
build_command(
|
|
234
235
|
'ffmpeg',
|
|
235
236
|
self._ffmpeg_parameters,
|
|
@@ -278,7 +279,7 @@ class MediaStream(Stream):
|
|
|
278
279
|
)
|
|
279
280
|
except LiveStreamFound:
|
|
280
281
|
live_stream = True
|
|
281
|
-
self.microphone.path =
|
|
282
|
+
self.microphone.path = list_to_cmd(
|
|
282
283
|
build_command(
|
|
283
284
|
'ffmpeg',
|
|
284
285
|
self._ffmpeg_parameters,
|
|
@@ -3,6 +3,7 @@ from typing import Union
|
|
|
3
3
|
|
|
4
4
|
from ntgcalls import MediaSource
|
|
5
5
|
|
|
6
|
+
from ...list_to_cmd import list_to_cmd
|
|
6
7
|
from ...media_devices.speaker_device import SpeakerDevice
|
|
7
8
|
from ...statictypes import statictypes
|
|
8
9
|
from ..raw.audio_parameters import AudioParameters
|
|
@@ -72,7 +73,7 @@ class RecordStream(Stream):
|
|
|
72
73
|
]
|
|
73
74
|
return AudioStream(
|
|
74
75
|
media_source=MediaSource.SHELL,
|
|
75
|
-
path=
|
|
76
|
+
path=list_to_cmd(commands),
|
|
76
77
|
parameters=raw_audio_parameters,
|
|
77
78
|
)
|
|
78
79
|
if isinstance(audio, SpeakerDevice):
|
|
@@ -81,6 +82,7 @@ class RecordStream(Stream):
|
|
|
81
82
|
path=audio.metadata,
|
|
82
83
|
parameters=raw_audio_parameters,
|
|
83
84
|
)
|
|
85
|
+
return None
|
|
84
86
|
|
|
85
87
|
@staticmethod
|
|
86
88
|
def _get_video_stream(enable):
|
pytgcalls/ytdlp.py
CHANGED
|
@@ -7,6 +7,7 @@ from typing import Tuple
|
|
|
7
7
|
|
|
8
8
|
from .exceptions import YtDlpError
|
|
9
9
|
from .ffmpeg import cleanup_commands
|
|
10
|
+
from .list_to_cmd import list_to_cmd
|
|
10
11
|
from .types.raw import VideoParameters
|
|
11
12
|
|
|
12
13
|
py_logger = logging.getLogger('pytgcalls')
|
|
@@ -37,7 +38,7 @@ class YtDlp:
|
|
|
37
38
|
'yt-dlp',
|
|
38
39
|
'-g',
|
|
39
40
|
'-f',
|
|
40
|
-
'bestvideo[vcodec
|
|
41
|
+
'bestvideo[vcodec~="(vp09|avc1)"]+m4a/best',
|
|
41
42
|
'-S',
|
|
42
43
|
'res:'
|
|
43
44
|
f'{min(video_parameters.width, video_parameters.height)}',
|
|
@@ -59,7 +60,7 @@ class YtDlp:
|
|
|
59
60
|
|
|
60
61
|
py_logger.log(
|
|
61
62
|
logging.DEBUG,
|
|
62
|
-
f'Running with "{
|
|
63
|
+
f'Running with "{list_to_cmd(commands)}" command',
|
|
63
64
|
)
|
|
64
65
|
try:
|
|
65
66
|
proc = await asyncio.create_subprocess_exec(
|
|
File without changes
|
|
File without changes
|