mc5-api-client 1.0.16__py3-none-any.whl → 1.0.18__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.
@@ -14,8 +14,11 @@ Provides easy-to-use methods with automatic clan detection and simplified syntax
14
14
  """
15
15
 
16
16
  from typing import Optional, Dict, Any, List
17
- from .client import MC5Client
17
+ from .telemetry import telemetry, report_error, report_usage, is_telemetry_enabled
18
+ from .debug import debug_function, debug_print, debug_request, debug_response, print_error_analysis
18
19
  from .exceptions import MC5APIError
20
+ from .client import MC5Client
21
+ from .platform import Platform
19
22
 
20
23
  class SimpleMC5Client:
21
24
  """
@@ -25,46 +28,74 @@ class SimpleMC5Client:
25
28
  for common operations.
26
29
  """
27
30
 
28
- def __init__(self, username: str, password: str):
31
+ def __init__(self, username: str, password: str, platform: Platform = Platform.PC):
29
32
  """
30
- Initialize the client with your MC5 credentials.
33
+ Initialize SimpleMC5Client.
31
34
 
32
35
  Args:
33
36
  username: Your MC5 username (e.g., "anonymous:your_credential")
34
37
  password: Your MC5 password
38
+ platform: Platform to use (PC or Android)
35
39
  """
36
40
  self.username = username
37
41
  self.password = password
38
- self.client = None
42
+ self.platform = platform
43
+ self.client = MC5Client(platform=platform) # Initialize the client without auto-auth
39
44
  self._clan_id = None
40
45
  self._profile = None
41
46
 
47
+ @debug_function
42
48
  def connect(self) -> bool:
43
49
  """
44
- Connect to MC5 and auto-detect your clan.
50
+ Connect to MC5 API with enhanced debugging.
45
51
 
46
52
  Returns:
47
53
  True if connection successful, False otherwise
48
54
  """
49
55
  try:
50
- # Create the client only when connecting
51
- self.client = MC5Client(self.username, self.password)
56
+ # debug_print(f"🔐 Connecting to MC5 API as {self.username[:10]}...")
52
57
 
53
- # Get profile info
54
- self._profile = self.client.get_profile()
58
+ # Authenticate
59
+ self.client.authenticate(self.username, self.password)
60
+ # debug_print("✅ Authentication successful", "success")
55
61
 
56
- # Auto-detect clan ID
57
- groups = self._profile.get('groups', [])
58
- if groups:
59
- self._clan_id = groups[0]
60
- print(f"✅ Connected! Auto-detected clan: {self._get_clan_name()}")
61
- return True
62
- else:
63
- print("⚠️ Connected but no clan found")
64
- return True
62
+ # Get profile
63
+ profile = self.client.get_profile()
64
+ if not profile:
65
+ debug_print("❌ Failed to get profile", "error")
66
+ return False
67
+
68
+ self._profile = profile
69
+ # debug_print("👤 Profile loaded: " + profile.get('name', 'Unknown'), "info")
70
+
71
+ # Auto-detect clan
72
+ clan_id = profile.get('_clan_id')
73
+ if clan_id:
74
+ self._clan_id = clan_id
75
+ # debug_print("🏰 Auto-detected clan: {clan_id}", "success")
65
76
 
77
+ # Try to get clan details
78
+ try:
79
+ clan_settings = self.client.get_clan_settings(clan_id)
80
+ if clan_settings:
81
+ clan_name = clan_settings.get('name', f'Clan_{clan_id[:8]}')
82
+ debug_print(f"🏰 Clan name: {clan_name}", "info")
83
+ except:
84
+ debug_print("⚠️ Could not get clan details", "warning")
85
+ else:
86
+ debug_print("ℹ️ No clan detected", "info")
87
+
88
+ self.connected = True
89
+ # debug_print("🎉 Connection successful!", "success")
90
+ return True
91
+
66
92
  except Exception as e:
67
- print(f"❌ Connection failed: {e}")
93
+ debug_print(f"❌ Connection failed: {e}", "error")
94
+ print_error_analysis(e)
95
+ report_error(e, "SimpleMC5Client.connect", {
96
+ "username": self.username[:10] + "..."
97
+ })
98
+ self.connected = False
68
99
  return False
69
100
 
70
101
  def _get_clan_name(self) -> str:
@@ -474,6 +505,329 @@ class SimpleMC5Client:
474
505
  except:
475
506
  pass
476
507
 
508
+ def remove_friend(self, target_user_id: str, message: str = "removed",
509
+ killsig_color: str = None, killsig_name: str = None) -> bool:
510
+ """
511
+ Send a friend removal notification message.
512
+
513
+ Args:
514
+ target_user_id: Target player's user ID
515
+ message: Message content (default: "removed")
516
+ killsig_color: Kill signature color (optional)
517
+ killsig_name: Kill signature name (optional)
518
+
519
+ Returns:
520
+ True if successful, False otherwise
521
+ """
522
+ try:
523
+ print(f"🔵 Sending friend removal notification to {target_user_id}...")
524
+ result = self.client.remove_friend(target_user_id, message, killsig_color, killsig_name)
525
+
526
+ if result and not result.get('error'):
527
+ print(f"✅ Friend removal notification sent to {target_user_id}")
528
+ return True
529
+ else:
530
+ print(f"❌ Failed to send friend removal notification: {result.get('error', 'Unknown error')}")
531
+ return False
532
+ except Exception as e:
533
+ print(f"❌ Error removing friend: {e}")
534
+ return False
535
+
536
+ def delete_friend_connection(self, target_user_id: str) -> bool:
537
+ """
538
+ Delete a friend connection (actual removal from friends list).
539
+
540
+ Args:
541
+ target_user_id: Target player's user ID
542
+
543
+ Returns:
544
+ True if successful, False otherwise
545
+ """
546
+ try:
547
+ print(f"🔴 Deleting friend connection with {target_user_id}...")
548
+ result = self.client.delete_friend_connection(target_user_id)
549
+
550
+ if result and not result.get('error'):
551
+ print(f"✅ Friend connection deleted: {target_user_id}")
552
+ return True
553
+ else:
554
+ print(f"❌ Failed to delete friend connection: {result.get('error', 'Unknown error')}")
555
+ return False
556
+ except Exception as e:
557
+ print(f"❌ Error deleting friend connection: {e}")
558
+ return False
559
+
560
+ def send_friend_request(self, target_user_id: str, alert_kairos: bool = True) -> bool:
561
+ """
562
+ Send a friend request to another player.
563
+
564
+ Args:
565
+ target_user_id: Target player's user ID
566
+ alert_kairos: Whether to send alert notification
567
+
568
+ Returns:
569
+ True if successful, False otherwise
570
+ """
571
+ try:
572
+ print(f"🤝 Sending friend request to {target_user_id}...")
573
+ result = self.client.send_friend_request(target_user_id, alert_kairos)
574
+
575
+ if result and not result.get('error'):
576
+ print(f"✅ Friend request sent to {target_user_id}")
577
+ return True
578
+ else:
579
+ print(f"❌ Failed to send friend request: {result.get('error', 'Unknown error')}")
580
+ return False
581
+ except Exception as e:
582
+ print(f"❌ Error sending friend request: {e}")
583
+ return False
584
+
585
+ def get_friend_connection_status(self, target_user_id: str) -> Optional[Dict[str, Any]]:
586
+ """
587
+ Get the connection status with a specific friend.
588
+
589
+ Args:
590
+ target_user_id: Target player's user ID
591
+
592
+ Returns:
593
+ Connection status information or None if error
594
+ """
595
+ try:
596
+ print(f"🔍 Checking friend connection status with {target_user_id}...")
597
+ result = self.client.get_friend_connection_status(target_user_id)
598
+
599
+ if result and not result.get('error'):
600
+ print(f"✅ Friend connection status retrieved")
601
+ return result
602
+ else:
603
+ print(f"ℹ️ No friend connection found with {target_user_id}")
604
+ return None
605
+ except Exception as e:
606
+ print(f"❌ Error checking friend connection status: {e}")
607
+ return None
608
+
609
+ # Event Management
610
+
611
+ def sign_up_for_event(self, event_id: str) -> bool:
612
+ """
613
+ Sign up for an event.
614
+
615
+ Args:
616
+ event_id: Event ID to sign up for
617
+
618
+ Returns:
619
+ True if successful, False otherwise
620
+ """
621
+ try:
622
+ print(f"🎯 Signing up for event: {event_id}")
623
+ result = self.client.sign_up_for_event(event_id)
624
+
625
+ if result and not result.get('error'):
626
+ print(f"✅ Successfully signed up for event {event_id}")
627
+ return True
628
+ else:
629
+ print(f"❌ Failed to sign up for event: {result.get('error', 'Unknown error')}")
630
+ return False
631
+ except Exception as e:
632
+ print(f"❌ Error signing up for event: {e}")
633
+ return False
634
+
635
+ def get_event_leaderboard(self, event_id: str, offset: int = 0, limit: int = 100) -> Optional[Dict[str, Any]]:
636
+ """
637
+ Get the leaderboard for a specific event.
638
+
639
+ Args:
640
+ event_id: Event ID
641
+ offset: Pagination offset (default: 0)
642
+ limit: Number of entries to retrieve (default: 100)
643
+
644
+ Returns:
645
+ Event leaderboard data or None if error
646
+ """
647
+ try:
648
+ print(f"🏆 Getting event leaderboard for {event_id}...")
649
+ result = self.client.get_event_leaderboard(event_id, offset, limit)
650
+
651
+ if result and 'data' in result:
652
+ print(f"✅ Retrieved {len(result['data'])} leaderboard entries")
653
+ return result
654
+ else:
655
+ print(f"❌ Failed to get event leaderboard")
656
+ return None
657
+ except Exception as e:
658
+ print(f"❌ Error getting event leaderboard: {e}")
659
+ return None
660
+
661
+ def get_my_event_leaderboard_entry(self, event_id: str, limit: int = 5) -> Optional[Dict[str, Any]]:
662
+ """
663
+ Get your entry and surrounding players in the event leaderboard.
664
+
665
+ Args:
666
+ event_id: Event ID
667
+ limit: Number of surrounding entries to show (default: 5)
668
+
669
+ Returns:
670
+ Your leaderboard entry with surrounding players or None if error
671
+ """
672
+ try:
673
+ print(f"🔍 Getting your event leaderboard entry for {event_id}...")
674
+ result = self.client.get_my_event_leaderboard_entry(event_id, limit)
675
+
676
+ if result and 'my_entry' in result:
677
+ my_rank = result['my_entry'].get('rank', 'Unknown')
678
+ my_score = result['my_entry'].get('score', 0)
679
+ print(f"✅ Your rank: {my_rank}, Score: {my_score}")
680
+ return result
681
+ else:
682
+ print(f"❌ Failed to get your event leaderboard entry")
683
+ return None
684
+ except Exception as e:
685
+ print(f"❌ Error getting your event leaderboard entry: {e}")
686
+ return None
687
+
688
+ # Squad/Group Management
689
+
690
+ def get_squad_invitations(self) -> List[Dict[str, Any]]:
691
+ """
692
+ Get all pending squad invitations.
693
+
694
+ Returns:
695
+ List of squad invitations or empty list if error
696
+ """
697
+ try:
698
+ print("📨 Getting squad invitations...")
699
+ invitations = self.client.get_squad_invitations()
700
+
701
+ if invitations:
702
+ print(f"✅ Found {len(invitations)} squad invitation(s)")
703
+ for i, invite in enumerate(invitations, 1):
704
+ squad_name = invite.get('group', {}).get('name', 'Unknown Squad')
705
+ requester = invite.get('requester', {}).get('name', 'Unknown Player')
706
+ print(f" {i}. {squad_name} from {requester}")
707
+ else:
708
+ print("ℹ️ No squad invitations found")
709
+
710
+ return invitations
711
+ except Exception as e:
712
+ print(f"❌ Error getting squad invitations: {e}")
713
+ return []
714
+
715
+ def accept_squad_invitation(self, invitation: Dict[str, Any]) -> bool:
716
+ """
717
+ Accept a squad invitation.
718
+
719
+ Args:
720
+ invitation: Squad invitation dictionary from get_squad_invitations()
721
+
722
+ Returns:
723
+ True if successful, False otherwise
724
+ """
725
+ try:
726
+ group_id = invitation.get('group_id')
727
+ message_id = invitation.get('id')
728
+ squad_name = invitation.get('group', {}).get('name', 'Unknown Squad')
729
+ requester = invitation.get('requester', {}).get('name', 'Unknown Player')
730
+
731
+ if not group_id or not message_id:
732
+ print("❌ Invalid invitation data")
733
+ return False
734
+
735
+ print(f"🎯 Accepting squad invitation: {squad_name} from {requester}")
736
+
737
+ # Get your profile data for optional parameters
738
+ profile = self.client.get_profile()
739
+ credential = profile.get('credential', '')
740
+
741
+ # Accept the invitation
742
+ result = self.client.accept_squad_invitation(
743
+ group_id=group_id,
744
+ credential=credential,
745
+ killsig_color=profile.get('_killsig_color'),
746
+ killsig_id=profile.get('_killsig_id'),
747
+ score=profile.get('_score'),
748
+ xp=profile.get('_xp')
749
+ )
750
+
751
+ if result:
752
+ print(f"✅ Successfully joined squad: {squad_name}")
753
+
754
+ # Delete the invitation message
755
+ print("🗑️ Cleaning up invitation message...")
756
+ self.client.delete_squad_invitation_message(message_id)
757
+ print("✅ Invitation message deleted")
758
+
759
+ return True
760
+ else:
761
+ print(f"❌ Failed to join squad: {squad_name}")
762
+ return False
763
+ except Exception as e:
764
+ print(f"❌ Error accepting squad invitation: {e}")
765
+ return False
766
+
767
+ def decline_squad_invitation(self, invitation: Dict[str, Any]) -> bool:
768
+ """
769
+ Decline a squad invitation.
770
+
771
+ Args:
772
+ invitation: Squad invitation dictionary from get_squad_invitations()
773
+
774
+ Returns:
775
+ True if successful, False otherwise
776
+ """
777
+ try:
778
+ message_id = invitation.get('id')
779
+ squad_name = invitation.get('group', {}).get('name', 'Unknown Squad')
780
+ requester = invitation.get('requester', {}).get('name', 'Unknown Player')
781
+
782
+ if not message_id:
783
+ print("❌ Invalid invitation data")
784
+ return False
785
+
786
+ print(f"🚫 Declining squad invitation: {squad_name} from {requester}")
787
+
788
+ # Decline the invitation (just delete the message)
789
+ result = self.client.decline_squad_invitation(message_id)
790
+
791
+ if result:
792
+ print(f"✅ Successfully declined squad invitation: {squad_name}")
793
+ return True
794
+ else:
795
+ print(f"❌ Failed to decline squad invitation: {squad_name}")
796
+ return False
797
+ except Exception as e:
798
+ print(f"❌ Error declining squad invitation: {e}")
799
+ return False
800
+
801
+ def accept_friend_request(self, request_id: str) -> Optional[Dict[str, Any]]:
802
+ """
803
+ Accept an incoming friend request.
804
+
805
+ Args:
806
+ request_id: Friend request ID to accept
807
+
808
+ Returns:
809
+ Connection details or None if error
810
+ """
811
+ try:
812
+ print(f"🤝 Accepting friend request: {request_id}")
813
+ result = self.client.accept_friend_request(request_id)
814
+
815
+ if result and 'requester' in result:
816
+ requester_name = result['requester'].get('name', 'Unknown')
817
+ print(f"✅ Successfully accepted friend request from {requester_name}")
818
+
819
+ # Show connection details
820
+ connection_type = result.get('connection_type', 'Unknown')
821
+ print(f" Connection type: {connection_type}")
822
+
823
+ return result
824
+ else:
825
+ print("❌ Failed to accept friend request")
826
+ return None
827
+ except Exception as e:
828
+ print(f"❌ Error accepting friend request: {e}")
829
+ return None
830
+
477
831
  def __enter__(self):
478
832
  """Context manager entry."""
479
833
  return self
@@ -553,6 +907,196 @@ def batch_search_players(dogtags: List[str], username: str, password: str) -> Di
553
907
  return results
554
908
 
555
909
 
910
+ def quick_remove_friend(target_user_id: str, username: str, password: str,
911
+ message: str = "removed") -> bool:
912
+ """
913
+ Quick remove a friend (send notification and delete connection).
914
+
915
+ Args:
916
+ target_user_id: Target player's user ID
917
+ username: Your MC5 username
918
+ password: Your MC5 password
919
+ message: Message content (default: "removed")
920
+
921
+ Returns:
922
+ True if successful, False otherwise
923
+ """
924
+ with SimpleMC5Client(username, password) as client:
925
+ if client.connect():
926
+ # Send notification first
927
+ notification_sent = client.remove_friend(target_user_id, message)
928
+ # Then delete connection
929
+ connection_deleted = client.delete_friend_connection(target_user_id)
930
+ return notification_sent and connection_deleted
931
+ return False
932
+
933
+
934
+ def quick_send_friend_request(target_user_id: str, username: str, password: str) -> bool:
935
+ """
936
+ Quick send a friend request.
937
+
938
+ Args:
939
+ target_user_id: Target player's user ID
940
+ username: Your MC5 username
941
+ password: Your MC5 password
942
+
943
+ Returns:
944
+ True if successful, False otherwise
945
+ """
946
+ with SimpleMC5Client(username, password) as client:
947
+ if client.connect():
948
+ return client.send_friend_request(target_user_id)
949
+ return False
950
+
951
+
952
+ def quick_check_friend_status(target_user_id: str, username: str, password: str) -> Optional[Dict[str, Any]]:
953
+ """
954
+ Quick check friend connection status.
955
+
956
+ Args:
957
+ target_user_id: Target player's user ID
958
+ username: Your MC5 username
959
+ password: Your MC5 password
960
+
961
+ Returns:
962
+ Connection status information or None if not found
963
+ """
964
+ with SimpleMC5Client(username, password) as client:
965
+ if client.connect():
966
+ return client.get_friend_connection_status(target_user_id)
967
+ return None
968
+
969
+
970
+ def quick_sign_up_for_event(event_id: str, username: str, password: str) -> bool:
971
+ """
972
+ Quick sign up for an event.
973
+
974
+ Args:
975
+ event_id: Event ID to sign up for
976
+ username: Your MC5 username
977
+ password: Your MC5 password
978
+
979
+ Returns:
980
+ True if successful, False otherwise
981
+ """
982
+ with SimpleMC5Client(username, password) as client:
983
+ if client.connect():
984
+ return client.sign_up_for_event(event_id)
985
+ return False
986
+
987
+
988
+ def quick_get_event_leaderboard(event_id: str, username: str, password: str,
989
+ offset: int = 0, limit: int = 100) -> Optional[Dict[str, Any]]:
990
+ """
991
+ Quick get event leaderboard.
992
+
993
+ Args:
994
+ event_id: Event ID
995
+ username: Your MC5 username
996
+ password: Your MC5 password
997
+ offset: Pagination offset (default: 0)
998
+ limit: Number of entries to retrieve (default: 100)
999
+
1000
+ Returns:
1001
+ Event leaderboard data or None if error
1002
+ """
1003
+ with SimpleMC5Client(username, password) as client:
1004
+ if client.connect():
1005
+ return client.get_event_leaderboard(event_id, offset, limit)
1006
+ return None
1007
+
1008
+
1009
+ def quick_get_my_event_rank(event_id: str, username: str, password: str,
1010
+ limit: int = 5) -> Optional[Dict[str, Any]]:
1011
+ """
1012
+ Quick get your event leaderboard entry and rank.
1013
+
1014
+ Args:
1015
+ event_id: Event ID
1016
+ username: Your MC5 username
1017
+ password: Your MC5 password
1018
+ limit: Number of surrounding entries to show (default: 5)
1019
+
1020
+ Returns:
1021
+ Your leaderboard entry with surrounding players or None if error
1022
+ """
1023
+ with SimpleMC5Client(username, password) as client:
1024
+ if client.connect():
1025
+ return client.get_my_event_leaderboard_entry(event_id, limit)
1026
+ return None
1027
+
1028
+
1029
+ def quick_get_squad_invitations(username: str, password: str) -> List[Dict[str, Any]]:
1030
+ """
1031
+ Quick get squad invitations.
1032
+
1033
+ Args:
1034
+ username: Your MC5 username
1035
+ password: Your MC5 password
1036
+
1037
+ Returns:
1038
+ List of squad invitations or empty list if error
1039
+ """
1040
+ with SimpleMC5Client(username, password) as client:
1041
+ if client.connect():
1042
+ return client.get_squad_invitations()
1043
+ return []
1044
+
1045
+
1046
+ def quick_accept_squad_invitation(invitation: Dict[str, Any], username: str, password: str) -> bool:
1047
+ """
1048
+ Quick accept a squad invitation.
1049
+
1050
+ Args:
1051
+ invitation: Squad invitation dictionary from quick_get_squad_invitations()
1052
+ username: Your MC5 username
1053
+ password: Your MC5 password
1054
+
1055
+ Returns:
1056
+ True if successful, False otherwise
1057
+ """
1058
+ with SimpleMC5Client(username, password) as client:
1059
+ if client.connect():
1060
+ return client.accept_squad_invitation(invitation)
1061
+ return False
1062
+
1063
+
1064
+ def quick_decline_squad_invitation(invitation: Dict[str, Any], username: str, password: str) -> bool:
1065
+ """
1066
+ Quick decline a squad invitation.
1067
+
1068
+ Args:
1069
+ invitation: Squad invitation dictionary from quick_get_squad_invitations()
1070
+ username: Your MC5 username
1071
+ password: Your MC5 password
1072
+
1073
+ Returns:
1074
+ True if successful, False otherwise
1075
+ """
1076
+ with SimpleMC5Client(username, password) as client:
1077
+ if client.connect():
1078
+ return client.decline_squad_invitation(invitation)
1079
+ return False
1080
+
1081
+
1082
+ def quick_accept_friend_request(request_id: str, username: str, password: str) -> Optional[Dict[str, Any]]:
1083
+ """
1084
+ Quick accept a friend request.
1085
+
1086
+ Args:
1087
+ request_id: Friend request ID to accept
1088
+ username: Your MC5 username
1089
+ password: Your MC5 password
1090
+
1091
+ Returns:
1092
+ Connection details or None if error
1093
+ """
1094
+ with SimpleMC5Client(username, password) as client:
1095
+ if client.connect():
1096
+ return client.accept_friend_request(request_id)
1097
+ return None
1098
+
1099
+
556
1100
  def clan_cleanup(username: str, password: str,
557
1101
  inactive_days: int = 30,
558
1102
  min_level: int = 10,