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.
Files changed (33) hide show
  1. {py_tgcalls-2.1.2b3.dist-info → py_tgcalls-2.2.0.dist-info}/METADATA +2 -2
  2. {py_tgcalls-2.1.2b3.dist-info → py_tgcalls-2.2.0.dist-info}/RECORD +33 -32
  3. {py_tgcalls-2.1.2b3.dist-info → py_tgcalls-2.2.0.dist-info}/WHEEL +1 -1
  4. pytgcalls/__version__.py +1 -1
  5. pytgcalls/exceptions.py +0 -7
  6. pytgcalls/ffmpeg.py +2 -2
  7. pytgcalls/filters.py +6 -2
  8. pytgcalls/list_to_cmd.py +11 -0
  9. pytgcalls/methods/calls/leave_call.py +4 -0
  10. pytgcalls/methods/internal/connect_call.py +10 -12
  11. pytgcalls/methods/internal/handle_mtproto_updates.py +8 -15
  12. pytgcalls/methods/stream/play.py +2 -1
  13. pytgcalls/mtproto/bridged_client.py +64 -2
  14. pytgcalls/mtproto/client_cache.py +65 -72
  15. pytgcalls/mtproto/hydrogram_client.py +132 -35
  16. pytgcalls/mtproto/mtproto_client.py +11 -0
  17. pytgcalls/mtproto/pyrogram_client.py +135 -43
  18. pytgcalls/mtproto/telethon_client.py +95 -35
  19. pytgcalls/mutex.py +3 -1
  20. pytgcalls/types/cache.py +10 -5
  21. pytgcalls/types/chats/group_call_participant.py +1 -8
  22. pytgcalls/types/chats/updated_group_call_participant.py +2 -0
  23. pytgcalls/types/dict.py +1 -1
  24. pytgcalls/types/flag.py +4 -3
  25. pytgcalls/types/list.py +1 -1
  26. pytgcalls/types/participant_list.py +3 -3
  27. pytgcalls/types/py_object.py +4 -2
  28. pytgcalls/types/stream/media_stream.py +5 -4
  29. pytgcalls/types/stream/record_stream.py +3 -1
  30. pytgcalls/types/stream/video_quality.py +3 -1
  31. pytgcalls/ytdlp.py +3 -2
  32. {py_tgcalls-2.1.2b3.dist-info → py_tgcalls-2.2.0.dist-info}/licenses/LICENSE +0 -0
  33. {py_tgcalls-2.1.2b3.dist-info → py_tgcalls-2.2.0.dist-info}/top_level.txt +0 -0
@@ -4,14 +4,18 @@ from typing import List
4
4
  from typing import Optional
5
5
  from typing import Union
6
6
 
7
- import pyrogram
8
7
  from ntgcalls import MediaSegmentQuality
9
8
  from ntgcalls import Protocol
10
9
  from pyrogram import Client
11
10
  from pyrogram import ContinuePropagation
11
+ from pyrogram.errors import AuthBytesInvalid
12
+ from pyrogram.errors import BadRequest
13
+ from pyrogram.errors import FileMigrate
12
14
  from pyrogram.errors import FloodWait
13
15
  from pyrogram.raw.base import InputPeer
14
16
  from pyrogram.raw.base import InputUser
17
+ from pyrogram.raw.functions.auth import ExportAuthorization
18
+ from pyrogram.raw.functions.auth import ImportAuthorization
15
19
  from pyrogram.raw.functions.channels import GetFullChannel
16
20
  from pyrogram.raw.functions.messages import GetDhConfig
17
21
  from pyrogram.raw.functions.messages import GetFullChat
@@ -19,6 +23,7 @@ from pyrogram.raw.functions.phone import AcceptCall
19
23
  from pyrogram.raw.functions.phone import ConfirmCall
20
24
  from pyrogram.raw.functions.phone import CreateGroupCall
21
25
  from pyrogram.raw.functions.phone import DiscardCall
26
+ from pyrogram.raw.functions.phone import DiscardGroupCall
22
27
  from pyrogram.raw.functions.phone import EditGroupCallParticipant
23
28
  from pyrogram.raw.functions.phone import GetGroupCall
24
29
  from pyrogram.raw.functions.phone import GetGroupCallStreamChannels
@@ -65,13 +70,13 @@ from pyrogram.raw.types import UpdatePhoneCall
65
70
  from pyrogram.raw.types import UpdatePhoneCallSignalingData
66
71
  from pyrogram.raw.types import Updates
67
72
  from pyrogram.raw.types.messages import DhConfig
73
+ from pyrogram.session import Auth
74
+ from pyrogram.session import Session
68
75
 
69
76
  from ..types import CallProtocol
70
77
  from ..types import ChatUpdate
71
78
  from ..types import GroupCallParticipant
72
79
  from ..types import RawCallUpdate
73
- from ..types import UpdatedGroupCallParticipant
74
- from ..version_manager import VersionManager
75
80
  from .bridged_client import BridgedClient
76
81
  from .client_cache import ClientCache
77
82
 
@@ -84,18 +89,12 @@ class PyrogramClient(BridgedClient):
84
89
  ):
85
90
  super().__init__()
86
91
  self._app: Client = client
87
- if VersionManager.version_tuple(
88
- pyrogram.__version__,
89
- ) > VersionManager.version_tuple(
90
- '2.0.0',
91
- ):
92
- self._app.send = self._app.invoke
93
92
  self._cache: ClientCache = ClientCache(
94
93
  cache_duration,
95
94
  self,
96
95
  )
97
96
 
98
- @self._app.on_raw_update(group=-1)
97
+ @self._app.on_raw_update(group=-9999)
99
98
  async def on_update(_, update, __, chats):
100
99
  if isinstance(
101
100
  update,
@@ -187,19 +186,23 @@ class PyrogramClient(BridgedClient):
187
186
  update,
188
187
  UpdateGroupCallParticipants,
189
188
  ):
190
- participants = update.participants
191
- for participant in participants:
192
- result = self._cache.set_participants_cache_call(
193
- update.call.id,
194
- self.parse_participant(participant),
189
+ for participant in update.participants:
190
+ chat_id = self._cache.get_chat_id(update.call.id)
191
+ p_updates = await self.diff_participants_update(
192
+ self._cache,
193
+ chat_id,
194
+ participant,
195
195
  )
196
- if result is not None:
197
- await self._propagate(
198
- UpdatedGroupCallParticipant(
199
- self._cache.get_chat_id(update.call.id),
200
- result,
201
- ),
196
+ for p_update in p_updates:
197
+ result = self._cache.set_participants_cache(
198
+ chat_id,
199
+ update.call.id,
200
+ p_update.action,
201
+ p_update.participant,
202
202
  )
203
+ if result is not None:
204
+ await self._propagate(p_update)
205
+
203
206
  if isinstance(
204
207
  update,
205
208
  UpdateGroupCall,
@@ -325,7 +328,7 @@ class PyrogramClient(BridgedClient):
325
328
  chat = await self._app.resolve_peer(chat_id)
326
329
  if isinstance(chat, InputPeerChannel):
327
330
  input_call = (
328
- await self._app.send(
331
+ await self._invoke(
329
332
  GetFullChannel(
330
333
  channel=InputChannel(
331
334
  channel_id=chat.channel_id,
@@ -336,14 +339,14 @@ class PyrogramClient(BridgedClient):
336
339
  ).full_chat.call
337
340
  else:
338
341
  input_call = (
339
- await self._app.send(
342
+ await self._invoke(
340
343
  GetFullChat(chat_id=chat.chat_id),
341
344
  )
342
345
  ).full_chat.call
343
346
 
344
347
  if input_call is not None:
345
348
  raw_call = (
346
- await self._app.send(
349
+ await self._invoke(
347
350
  GetGroupCall(
348
351
  call=input_call,
349
352
  limit=-1,
@@ -353,9 +356,10 @@ class PyrogramClient(BridgedClient):
353
356
  call: GroupCall = raw_call.call
354
357
  participants: List[GroupCallParticipant] = raw_call.participants
355
358
  for participant in participants:
356
- self._cache.set_participants_cache_chat(
359
+ self._cache.set_participants_cache(
357
360
  chat_id,
358
361
  call.id,
362
+ self.parse_participant_action(participant),
359
363
  self.parse_participant(participant),
360
364
  )
361
365
  if call.schedule_date is not None:
@@ -364,7 +368,7 @@ class PyrogramClient(BridgedClient):
364
368
  return input_call
365
369
 
366
370
  async def get_dhc(self) -> DhConfig:
367
- return await self._app.send(
371
+ return await self._invoke(
368
372
  GetDhConfig(
369
373
  version=0,
370
374
  random_length=256,
@@ -386,7 +390,7 @@ class PyrogramClient(BridgedClient):
386
390
  participants = []
387
391
  next_offset = ''
388
392
  while True:
389
- result = await self._app.send(
393
+ result = await self._invoke(
390
394
  GetGroupParticipants(
391
395
  call=input_call,
392
396
  ids=[],
@@ -413,7 +417,7 @@ class PyrogramClient(BridgedClient):
413
417
  ) -> str:
414
418
  chat_call = await self._cache.get_full_chat(chat_id)
415
419
  if chat_call is not None:
416
- result: Updates = await self._app.send(
420
+ result: Updates = await self._invoke(
417
421
  JoinGroupCall(
418
422
  call=chat_call,
419
423
  params=DataJSON(data=json_join),
@@ -430,8 +434,10 @@ class PyrogramClient(BridgedClient):
430
434
  ):
431
435
  participants = update.participants
432
436
  for participant in participants:
433
- self._cache.set_participants_cache_call(
437
+ self._cache.set_participants_cache(
438
+ chat_id,
434
439
  update.call.id,
440
+ self.parse_participant_action(participant),
435
441
  self.parse_participant(participant),
436
442
  )
437
443
  if isinstance(update, UpdateGroupCallConnection):
@@ -446,7 +452,7 @@ class PyrogramClient(BridgedClient):
446
452
  ):
447
453
  chat_call = await self._cache.get_full_chat(chat_id)
448
454
  if chat_call is not None:
449
- result: Updates = await self._app.send(
455
+ result: Updates = await self._invoke(
450
456
  JoinGroupCallPresentation(
451
457
  call=chat_call,
452
458
  params=DataJSON(data=json_join),
@@ -464,7 +470,7 @@ class PyrogramClient(BridgedClient):
464
470
  ):
465
471
  chat_call = await self._cache.get_full_chat(chat_id)
466
472
  if chat_call is not None:
467
- await self._app.send(
473
+ await self._invoke(
468
474
  LeaveGroupCallPresentation(
469
475
  call=chat_call,
470
476
  ),
@@ -477,7 +483,7 @@ class PyrogramClient(BridgedClient):
477
483
  protocol: Protocol,
478
484
  has_video: bool,
479
485
  ):
480
- update = await self._app.invoke(
486
+ update = await self._invoke(
481
487
  RequestCall(
482
488
  user_id=await self.resolve_peer(user_id),
483
489
  random_id=self.rnd_id(),
@@ -500,7 +506,7 @@ class PyrogramClient(BridgedClient):
500
506
  g_b: bytes,
501
507
  protocol: Protocol,
502
508
  ):
503
- await self._app.invoke(
509
+ await self._invoke(
504
510
  AcceptCall(
505
511
  peer=self._cache.get_phone_call(user_id),
506
512
  g_b=g_b,
@@ -516,7 +522,7 @@ class PyrogramClient(BridgedClient):
516
522
  protocol: Protocol,
517
523
  ) -> CallProtocol:
518
524
  res = (
519
- await self._app.invoke(
525
+ await self._invoke(
520
526
  ConfirmCall(
521
527
  peer=self._cache.get_phone_call(user_id),
522
528
  g_a=g_a,
@@ -536,7 +542,7 @@ class PyrogramClient(BridgedClient):
536
542
  user_id: int,
537
543
  data: bytes,
538
544
  ):
539
- await self._app.invoke(
545
+ await self._invoke(
540
546
  SendSignalingData(
541
547
  peer=self._cache.get_phone_call(user_id),
542
548
  data=data,
@@ -547,7 +553,7 @@ class PyrogramClient(BridgedClient):
547
553
  self,
548
554
  chat_id: int,
549
555
  ):
550
- result: Updates = await self._app.send(
556
+ result: Updates = await self._invoke(
551
557
  CreateGroupCall(
552
558
  peer=await self.resolve_peer(chat_id),
553
559
  random_id=self.rnd_id(),
@@ -577,13 +583,26 @@ class PyrogramClient(BridgedClient):
577
583
  ):
578
584
  chat_call = await self._cache.get_full_chat(chat_id)
579
585
  if chat_call is not None:
580
- await self._app.send(
586
+ await self._invoke(
581
587
  LeaveGroupCall(
582
588
  call=chat_call,
583
589
  source=0,
584
590
  ),
585
591
  )
586
592
 
593
+ async def close_voice_chat(
594
+ self,
595
+ chat_id: int,
596
+ ):
597
+ chat_call = await self._cache.get_full_chat(chat_id)
598
+ if chat_call is not None:
599
+ await self._invoke(
600
+ DiscardGroupCall(
601
+ call=chat_call,
602
+ ),
603
+ )
604
+ self._cache.drop_cache(chat_id)
605
+
587
606
  async def discard_call(
588
607
  self,
589
608
  chat_id: int,
@@ -597,7 +616,7 @@ class PyrogramClient(BridgedClient):
597
616
  if is_missed
598
617
  else PhoneCallDiscardReasonHangup()
599
618
  )
600
- await self._app.invoke(
619
+ await self._invoke(
601
620
  DiscardCall(
602
621
  peer=peer,
603
622
  duration=0,
@@ -616,7 +635,7 @@ class PyrogramClient(BridgedClient):
616
635
  ):
617
636
  chat_call = await self._cache.get_full_chat(chat_id)
618
637
  if chat_call is not None:
619
- await self._app.send(
638
+ await self._invoke(
620
639
  EditGroupCallParticipant(
621
640
  call=chat_call,
622
641
  participant=participant,
@@ -637,7 +656,7 @@ class PyrogramClient(BridgedClient):
637
656
  if chat_call is not None:
638
657
  try:
639
658
  return (
640
- await self._app.send(
659
+ await self._invoke(
641
660
  GetFile(
642
661
  location=InputGroupCallStream(
643
662
  call=chat_call,
@@ -651,6 +670,7 @@ class PyrogramClient(BridgedClient):
651
670
  offset=0,
652
671
  limit=limit,
653
672
  ),
673
+ chat_id=chat_id,
654
674
  sleep_threshold=0,
655
675
  )
656
676
  ).bytes
@@ -664,12 +684,12 @@ class PyrogramClient(BridgedClient):
664
684
  ):
665
685
  chat_call = await self._cache.get_full_chat(chat_id)
666
686
  if chat_call is not None:
667
- # noinspection PyBroadException
668
687
  channels = (
669
- await self._app.send(
688
+ await self._invoke(
670
689
  GetGroupCallStreamChannels(
671
690
  call=chat_call,
672
691
  ),
692
+ chat_id=chat_id,
673
693
  )
674
694
  ).channels
675
695
  if len(channels) > 0:
@@ -688,7 +708,7 @@ class PyrogramClient(BridgedClient):
688
708
  ):
689
709
  chat_call = await self._cache.get_full_chat(chat_id)
690
710
  if chat_call is not None:
691
- await self._app.send(
711
+ await self._invoke(
692
712
  EditGroupCallParticipant(
693
713
  call=chat_call,
694
714
  participant=participant,
@@ -727,5 +747,77 @@ class PyrogramClient(BridgedClient):
727
747
  def no_updates(self):
728
748
  return self._app.no_updates
729
749
 
750
+ async def _invoke(
751
+ self,
752
+ request,
753
+ dc_id: Optional[int] = None,
754
+ chat_id: Optional[int] = None,
755
+ sleep_threshold: Optional[int] = None,
756
+ ):
757
+ if chat_id is not None:
758
+ dc_id = self._cache.get_dc_call(chat_id)
759
+ if dc_id is None:
760
+ session = self._app
761
+ else:
762
+ session = self._app.media_sessions.get(dc_id)
763
+ if not session:
764
+ session = self._app.media_sessions[dc_id] = Session(
765
+ self._app,
766
+ dc_id,
767
+ await Auth(
768
+ self._app,
769
+ dc_id,
770
+ await self._app.storage.test_mode(),
771
+ ).create()
772
+ if dc_id != await self._app.storage.dc_id()
773
+ else await self._app.storage.auth_key(),
774
+ await self._app.storage.test_mode(),
775
+ is_media=True,
776
+ )
777
+ await session.start()
778
+ if dc_id != await self._app.storage.dc_id():
779
+ for _ in range(3):
780
+ exported_auth = await self._invoke(
781
+ ExportAuthorization(
782
+ dc_id=dc_id,
783
+ ),
784
+ )
785
+
786
+ try:
787
+ await session.invoke(
788
+ ImportAuthorization(
789
+ id=exported_auth.id,
790
+ bytes=exported_auth.bytes,
791
+ ),
792
+ )
793
+ except AuthBytesInvalid:
794
+ continue
795
+ else:
796
+ break
797
+ else:
798
+ raise AuthBytesInvalid
799
+ try:
800
+ return await session.invoke(
801
+ request,
802
+ sleep_threshold=sleep_threshold,
803
+ )
804
+ except (BadRequest, FileMigrate) as e:
805
+ dc_new = BridgedClient.extract_dc(
806
+ str(e),
807
+ )
808
+ if dc_new is not None:
809
+ if chat_id is not None:
810
+ self._cache.set_dc_call(
811
+ chat_id,
812
+ dc_new,
813
+ )
814
+ return await self._invoke(
815
+ request,
816
+ dc_new,
817
+ chat_id,
818
+ sleep_threshold,
819
+ )
820
+ raise
821
+
730
822
  async def start(self):
731
823
  await self._app.start()