mc5-api-client 1.0.4__py3-none-any.whl → 1.0.6__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.
- mc5_api_client/__init__.py +1 -1
- mc5_api_client/client.py +407 -79
- {mc5_api_client-1.0.4.dist-info → mc5_api_client-1.0.6.dist-info}/METADATA +212 -103
- mc5_api_client-1.0.6.dist-info/RECORD +12 -0
- {mc5_api_client-1.0.4.dist-info → mc5_api_client-1.0.6.dist-info}/WHEEL +1 -1
- mc5_api_client-1.0.4.dist-info/RECORD +0 -12
- {mc5_api_client-1.0.4.dist-info → mc5_api_client-1.0.6.dist-info}/entry_points.txt +0 -0
- {mc5_api_client-1.0.4.dist-info → mc5_api_client-1.0.6.dist-info/licenses}/LICENSE +0 -0
- {mc5_api_client-1.0.4.dist-info → mc5_api_client-1.0.6.dist-info}/top_level.txt +0 -0
mc5_api_client/__init__.py
CHANGED
mc5_api_client/client.py
CHANGED
|
@@ -38,6 +38,7 @@ class MC5Client:
|
|
|
38
38
|
BASE_URLS = {
|
|
39
39
|
"auth": "https://eur-janus.gameloft.com:443",
|
|
40
40
|
"osiris": "https://eur-osiris.gameloft.com:443",
|
|
41
|
+
"janus": "https://eur-janus.gameloft.com",
|
|
41
42
|
"olympus": "https://eur-olympus.gameloft.com:443",
|
|
42
43
|
"iris": "https://eur-iris.gameloft.com:443",
|
|
43
44
|
"hermes": "https://eur-hermes.gameloft.com",
|
|
@@ -1149,16 +1150,20 @@ class MC5Client:
|
|
|
1149
1150
|
|
|
1150
1151
|
def get_alias_info(self, alias_id: str) -> Dict[str, Any]:
|
|
1151
1152
|
"""
|
|
1152
|
-
|
|
1153
|
+
Retrieve player information using alias/dogtag.
|
|
1153
1154
|
|
|
1154
1155
|
Args:
|
|
1155
|
-
alias_id:
|
|
1156
|
+
alias_id: Alias or dogtag identifier
|
|
1156
1157
|
|
|
1157
1158
|
Returns:
|
|
1158
|
-
|
|
1159
|
+
Player information including credential and account ID
|
|
1159
1160
|
"""
|
|
1160
|
-
url = f"{self.BASE_URLS['
|
|
1161
|
-
|
|
1161
|
+
url = f"{self.BASE_URLS['janus']}/games/mygame/alias/{alias_id}"
|
|
1162
|
+
params = {
|
|
1163
|
+
"access_token": self._token_data["access_token"]
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
return self._make_request("GET", url, params=params)
|
|
1162
1167
|
|
|
1163
1168
|
def convert_dogtag_to_alias(self, dogtag: str) -> str:
|
|
1164
1169
|
"""
|
|
@@ -1563,63 +1568,48 @@ class MC5Client:
|
|
|
1563
1568
|
|
|
1564
1569
|
# Alias/Dogtags System
|
|
1565
1570
|
|
|
1571
|
+
# Dogtag conversion mappings
|
|
1572
|
+
DOGTAG_SWAP = {
|
|
1573
|
+
'0': '8', '1': '9', '2': '0', '3': '1', '4': '2', '5': '3',
|
|
1574
|
+
'6': '4', '7': '5', '8': '6', '9': '7',
|
|
1575
|
+
'a': 'y', 'b': 'z', 'c': 'a', 'd': 'b', 'e': 'c', 'f': 'd',
|
|
1576
|
+
'g': 'e', 'h': 'f', 'i': 'g', 'j': 'h', 'k': 'i', 'l': 'j',
|
|
1577
|
+
'm': 'k', 'n': 'l', 'o': 'm', 'p': 'n', 'q': 'o', 'r': 'p',
|
|
1578
|
+
's': 'q', 't': 'r', 'u': 's', 'v': 't', 'w': 'u', 'x': 'v',
|
|
1579
|
+
'y': 'w', 'z': 'x'
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
REVERSE_DOGTAG_SWAP = {v: k for k, v in DOGTAG_SWAP.items()}
|
|
1583
|
+
|
|
1566
1584
|
def convert_dogtag_to_alias(self, dogtag: str) -> str:
|
|
1567
1585
|
"""
|
|
1568
|
-
Convert a dogtag (player ID) to alias format.
|
|
1586
|
+
Convert a dogtag (player ID) to alias format using the correct MC5 mapping.
|
|
1569
1587
|
|
|
1570
1588
|
Args:
|
|
1571
|
-
dogtag: Dogtag in XXXX format (hexadecimal)
|
|
1589
|
+
dogtag: Dogtag in XXXX format (hexadecimal), can be 4-8 characters
|
|
1572
1590
|
|
|
1573
1591
|
Returns:
|
|
1574
1592
|
Alias string
|
|
1575
1593
|
"""
|
|
1576
|
-
if not dogtag or len(dogtag)
|
|
1594
|
+
if not dogtag or len(dogtag) < 4 or len(dogtag) > 8:
|
|
1577
1595
|
return dogtag
|
|
1578
1596
|
|
|
1579
|
-
|
|
1580
|
-
for char in dogtag.lower():
|
|
1581
|
-
if char.isdigit():
|
|
1582
|
-
# Digit: subtract 2 using modulo 10 arithmetic
|
|
1583
|
-
digit = int(char)
|
|
1584
|
-
new_digit = (digit - 2) % 10
|
|
1585
|
-
alias += str(new_digit)
|
|
1586
|
-
elif char.isalpha():
|
|
1587
|
-
# Letter: subtract 2 from ASCII value
|
|
1588
|
-
new_char = chr(ord(char) - 2)
|
|
1589
|
-
alias += new_char
|
|
1590
|
-
else:
|
|
1591
|
-
alias += char
|
|
1592
|
-
|
|
1593
|
-
return alias
|
|
1597
|
+
return ''.join(self.DOGTAG_SWAP.get(c, c) for c in dogtag.lower())
|
|
1594
1598
|
|
|
1595
1599
|
def convert_alias_to_dogtag(self, alias: str) -> str:
|
|
1596
1600
|
"""
|
|
1597
|
-
Convert an alias back to dogtag format.
|
|
1601
|
+
Convert an alias back to dogtag format using the correct MC5 mapping.
|
|
1598
1602
|
|
|
1599
1603
|
Args:
|
|
1600
1604
|
alias: Alias string
|
|
1601
1605
|
|
|
1602
1606
|
Returns:
|
|
1603
|
-
Dogtag in XXXX format
|
|
1607
|
+
Dogtag in XXXX format (hexadecimal)
|
|
1604
1608
|
"""
|
|
1605
|
-
if not alias
|
|
1609
|
+
if not alias:
|
|
1606
1610
|
return alias
|
|
1607
1611
|
|
|
1608
|
-
|
|
1609
|
-
for char in alias.lower():
|
|
1610
|
-
if char.isdigit():
|
|
1611
|
-
# Digit: add 2 using modulo 10 arithmetic
|
|
1612
|
-
digit = int(char)
|
|
1613
|
-
new_digit = (digit + 2) % 10
|
|
1614
|
-
dogtag += str(new_digit)
|
|
1615
|
-
elif char.isalpha():
|
|
1616
|
-
# Letter: add 2 to ASCII value
|
|
1617
|
-
new_char = chr(ord(char) + 2)
|
|
1618
|
-
dogtag += new_char
|
|
1619
|
-
else:
|
|
1620
|
-
dogtag += char
|
|
1621
|
-
|
|
1622
|
-
return dogtag
|
|
1612
|
+
return ''.join(self.REVERSE_DOGTAG_SWAP.get(c, c) for c in alias.lower())
|
|
1623
1613
|
|
|
1624
1614
|
def get_alias_info(self, alias_id: str) -> Dict[str, Any]:
|
|
1625
1615
|
"""
|
|
@@ -1631,10 +1621,6 @@ class MC5Client:
|
|
|
1631
1621
|
Returns:
|
|
1632
1622
|
Player account information
|
|
1633
1623
|
"""
|
|
1634
|
-
# Convert to alias if it's a dogtag
|
|
1635
|
-
if len(alias_id) == 4 and all(c in '0123456789abcdefABCDEF' for c in alias_id):
|
|
1636
|
-
alias_id = self.convert_dogtag_to_alias(alias_id)
|
|
1637
|
-
|
|
1638
1624
|
url = f"{self.BASE_URLS['janus']}/games/mygame/alias/{alias_id}"
|
|
1639
1625
|
return self._make_request("GET", url)
|
|
1640
1626
|
|
|
@@ -1672,15 +1658,21 @@ class MC5Client:
|
|
|
1672
1658
|
Returns:
|
|
1673
1659
|
List of game objects with detailed information
|
|
1674
1660
|
"""
|
|
1675
|
-
#
|
|
1676
|
-
# For now, using a placeholder URL
|
|
1661
|
+
# Use timestamp-based URL for dynamic content
|
|
1677
1662
|
import time
|
|
1678
|
-
|
|
1663
|
+
timestamp = int(time.time())
|
|
1664
|
+
url = f"https://iris16-gold.gameloft.com/1875/game_object_{timestamp}"
|
|
1665
|
+
|
|
1679
1666
|
try:
|
|
1680
1667
|
return self._make_request("GET", url)
|
|
1681
1668
|
except:
|
|
1682
|
-
# Fallback to
|
|
1683
|
-
|
|
1669
|
+
# Fallback to static URL if dynamic fails
|
|
1670
|
+
fallback_url = "https://iris16-gold.gameloft.com/1875/game_object_1747885487.1257186"
|
|
1671
|
+
try:
|
|
1672
|
+
return self._make_request("GET", fallback_url)
|
|
1673
|
+
except:
|
|
1674
|
+
# Return empty catalog if both fail
|
|
1675
|
+
return []
|
|
1684
1676
|
|
|
1685
1677
|
def get_service_urls(self) -> Dict[str, str]:
|
|
1686
1678
|
"""
|
|
@@ -1758,12 +1750,27 @@ class MC5Client:
|
|
|
1758
1750
|
|
|
1759
1751
|
return self._make_request("POST", url, data=data, headers=headers)
|
|
1760
1752
|
|
|
1753
|
+
def get_complete_player_stats(self, credentials: List[str]) -> Dict[str, Any]:
|
|
1754
|
+
"""
|
|
1755
|
+
Get complete player statistics with all available fields.
|
|
1756
|
+
|
|
1757
|
+
Args:
|
|
1758
|
+
credentials: List of player credentials to fetch
|
|
1759
|
+
|
|
1760
|
+
Returns:
|
|
1761
|
+
Dictionary with complete player profiles
|
|
1762
|
+
"""
|
|
1763
|
+
# Try to get all possible fields
|
|
1764
|
+
all_fields = ['_game_save', 'inventory', 'statistics', 'profile', 'achievements']
|
|
1765
|
+
return self.get_batch_profiles(credentials, all_fields)
|
|
1766
|
+
|
|
1761
1767
|
def get_player_stats_by_dogtag(self, dogtag: str) -> Dict[str, Any]:
|
|
1762
1768
|
"""
|
|
1763
1769
|
Get detailed player statistics using their dogtag (in-game ID).
|
|
1770
|
+
Follows the exact API flow: dogtag → alias → janus lookup → batch profiles.
|
|
1764
1771
|
|
|
1765
1772
|
Args:
|
|
1766
|
-
dogtag: Player's dogtag in XXXX format (hexadecimal)
|
|
1773
|
+
dogtag: Player's dogtag in XXXX format (hexadecimal), can be 4-8 characters
|
|
1767
1774
|
|
|
1768
1775
|
Returns:
|
|
1769
1776
|
Player statistics and profile information
|
|
@@ -1771,42 +1778,300 @@ class MC5Client:
|
|
|
1771
1778
|
# Convert dogtag to alias for API lookup
|
|
1772
1779
|
alias = self.convert_dogtag_to_alias(dogtag)
|
|
1773
1780
|
|
|
1774
|
-
# Get player info using alias
|
|
1775
|
-
player_info = self.get_alias_info(alias)
|
|
1776
|
-
if not player_info.get('credential'):
|
|
1777
|
-
return {'error': f'Player not found for dogtag: {dogtag}', 'alias': alias}
|
|
1778
|
-
|
|
1779
|
-
# Get detailed stats using the credential
|
|
1781
|
+
# Get player info using alias from janus endpoint
|
|
1780
1782
|
try:
|
|
1781
|
-
|
|
1783
|
+
player_info = self.get_alias_info(alias)
|
|
1784
|
+
if not player_info.get('credential'):
|
|
1785
|
+
return {
|
|
1786
|
+
'error': f'Player not found for dogtag: {dogtag}',
|
|
1787
|
+
'dogtag': dogtag,
|
|
1788
|
+
'alias': alias,
|
|
1789
|
+
'janus_response': player_info
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1792
|
+
# Get detailed stats using the credential from batch profiles endpoint
|
|
1793
|
+
try:
|
|
1794
|
+
stats = self.get_batch_profiles([player_info['credential']])
|
|
1795
|
+
|
|
1796
|
+
# Add dogtag and alias info to the response
|
|
1797
|
+
if player_info['credential'] in stats:
|
|
1798
|
+
stats[player_info['credential']]['dogtag'] = dogtag
|
|
1799
|
+
stats[player_info['credential']]['alias'] = alias
|
|
1800
|
+
stats[player_info['credential']]['player_info'] = player_info
|
|
1801
|
+
stats[player_info['credential']]['janus_response'] = player_info
|
|
1802
|
+
|
|
1803
|
+
return stats
|
|
1804
|
+
|
|
1805
|
+
except Exception as e:
|
|
1806
|
+
return {
|
|
1807
|
+
'error': f'Failed to get stats for dogtag {dogtag}: {e}',
|
|
1808
|
+
'dogtag': dogtag,
|
|
1809
|
+
'alias': alias,
|
|
1810
|
+
'player_info': player_info,
|
|
1811
|
+
'janus_response': player_info
|
|
1812
|
+
}
|
|
1813
|
+
except Exception as e:
|
|
1814
|
+
return {
|
|
1815
|
+
'error': f'Failed to lookup alias {alias} for dogtag {dogtag}: {e}',
|
|
1816
|
+
'dogtag': dogtag,
|
|
1817
|
+
'alias': alias
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
# Clan Management & Profile Operations
|
|
1821
|
+
|
|
1822
|
+
def get_profile(self) -> Dict[str, Any]:
|
|
1823
|
+
"""
|
|
1824
|
+
Retrieve player profile details including name, groups, and last time played.
|
|
1825
|
+
|
|
1826
|
+
Returns:
|
|
1827
|
+
Player profile information
|
|
1828
|
+
"""
|
|
1829
|
+
url = f"{self.BASE_URLS['osiris']}/accounts/me"
|
|
1830
|
+
params = {
|
|
1831
|
+
"access_token": self._token_data["access_token"]
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
return self._make_request("GET", url, params=params)
|
|
1835
|
+
|
|
1836
|
+
def update_profile(self, name: str = None, groups: str = None, games: str = None,
|
|
1837
|
+
credential: str = None, fed_id: str = None) -> Dict[str, Any]:
|
|
1838
|
+
"""
|
|
1839
|
+
Update player profile (name, groups, games data).
|
|
1840
|
+
|
|
1841
|
+
Args:
|
|
1842
|
+
name: Player nickname
|
|
1843
|
+
groups: Comma-separated clan IDs
|
|
1844
|
+
games: JSON string with game data
|
|
1845
|
+
credential: Player credential
|
|
1846
|
+
fed_id: Federated ID
|
|
1847
|
+
|
|
1848
|
+
Returns:
|
|
1849
|
+
Update result
|
|
1850
|
+
"""
|
|
1851
|
+
url = f"{self.BASE_URLS['osiris']}/accounts/me"
|
|
1852
|
+
|
|
1853
|
+
data = {
|
|
1854
|
+
"access_token": self._token_data["access_token"],
|
|
1855
|
+
"timestamp": str(int(time.time()))
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1858
|
+
if name is not None:
|
|
1859
|
+
data["name"] = name
|
|
1860
|
+
if groups is not None:
|
|
1861
|
+
data["groups"] = groups
|
|
1862
|
+
if games is not None:
|
|
1863
|
+
data["games"] = games
|
|
1864
|
+
if credential is not None:
|
|
1865
|
+
data["credential"] = credential
|
|
1866
|
+
if fed_id is not None:
|
|
1867
|
+
data["fed_id"] = fed_id
|
|
1868
|
+
|
|
1869
|
+
return self._make_request("POST", url, data=data)
|
|
1870
|
+
|
|
1871
|
+
def get_clan_members(self, clan_id: str, offset: int = 0) -> List[Dict[str, Any]]:
|
|
1872
|
+
"""
|
|
1873
|
+
Get all members of a clan.
|
|
1874
|
+
|
|
1875
|
+
Args:
|
|
1876
|
+
clan_id: The unique identifier of the clan
|
|
1877
|
+
offset: Number of results to skip for pagination
|
|
1878
|
+
|
|
1879
|
+
Returns:
|
|
1880
|
+
List of clan members with their details
|
|
1881
|
+
"""
|
|
1882
|
+
url = f"{self.BASE_URLS['osiris']}/groups/{clan_id}/members"
|
|
1883
|
+
params = {
|
|
1884
|
+
"access_token": self._token_data["access_token"],
|
|
1885
|
+
"group_id": clan_id,
|
|
1886
|
+
"offset": str(offset)
|
|
1887
|
+
}
|
|
1888
|
+
|
|
1889
|
+
response = self._make_request("GET", url, params=params)
|
|
1890
|
+
return response if isinstance(response, list) else []
|
|
1891
|
+
|
|
1892
|
+
def get_clan_info(self, clan_id: str) -> Dict[str, Any]:
|
|
1893
|
+
"""
|
|
1894
|
+
Get detailed information about a clan.
|
|
1895
|
+
|
|
1896
|
+
Args:
|
|
1897
|
+
clan_id: The unique identifier of the clan
|
|
1898
|
+
|
|
1899
|
+
Returns:
|
|
1900
|
+
Clan information including settings
|
|
1901
|
+
"""
|
|
1902
|
+
url = f"{self.BASE_URLS['osiris']}/groups/{clan_id}"
|
|
1903
|
+
params = {
|
|
1904
|
+
"access_token": self._token_data["access_token"]
|
|
1905
|
+
}
|
|
1906
|
+
|
|
1907
|
+
return self._make_request("GET", url, params=params)
|
|
1908
|
+
|
|
1909
|
+
def update_clan_settings(self, clan_id: str, name: str = None, description: str = None,
|
|
1910
|
+
rating: str = None, score: str = None, member_limit: str = None,
|
|
1911
|
+
membership: str = None, logo: str = None, logo_primary_color: str = None,
|
|
1912
|
+
logo_secondary_color: str = None, min_join_value: str = None,
|
|
1913
|
+
xp: str = None, currency: str = None, killsig_id: str = None,
|
|
1914
|
+
active_clan_label: str = None, active_member_count: str = None,
|
|
1915
|
+
active_clan_threshold: str = None) -> Dict[str, Any]:
|
|
1916
|
+
"""
|
|
1917
|
+
Update clan settings and information.
|
|
1918
|
+
|
|
1919
|
+
Args:
|
|
1920
|
+
clan_id: The unique identifier of the clan
|
|
1921
|
+
name: Clan name
|
|
1922
|
+
description: Clan description
|
|
1923
|
+
rating: Clan rating
|
|
1924
|
+
score: Clan score
|
|
1925
|
+
member_limit: Maximum number of members
|
|
1926
|
+
membership: Membership type (open, owner_approved, member_approved, closed)
|
|
1927
|
+
logo: Logo ID
|
|
1928
|
+
logo_primary_color: Primary logo color (0-16777215)
|
|
1929
|
+
logo_secondary_color: Secondary logo color (0-16777215)
|
|
1930
|
+
min_join_value: Minimum join value
|
|
1931
|
+
xp: Clan XP (max 10000)
|
|
1932
|
+
currency: Clan currency
|
|
1933
|
+
killsig_id: Kill sign ID
|
|
1934
|
+
active_clan_label: Whether clan label is active (true/false)
|
|
1935
|
+
active_member_count: Active member count
|
|
1936
|
+
active_clan_threshold: Active member threshold
|
|
1937
|
+
|
|
1938
|
+
Returns:
|
|
1939
|
+
Update result
|
|
1940
|
+
"""
|
|
1941
|
+
url = f"{self.BASE_URLS['osiris']}/groups/{clan_id}"
|
|
1942
|
+
|
|
1943
|
+
# Get current profile for required fields
|
|
1944
|
+
profile = self.get_profile()
|
|
1945
|
+
|
|
1946
|
+
data = {
|
|
1947
|
+
"access_token": self._token_data["access_token"],
|
|
1948
|
+
"_anonId": profile.get("credential", ""),
|
|
1949
|
+
"_fedId": profile.get("fed_id", ""),
|
|
1950
|
+
"timestamp": str(int(time.time()))
|
|
1951
|
+
}
|
|
1952
|
+
|
|
1953
|
+
# Add optional parameters
|
|
1954
|
+
if name is not None:
|
|
1955
|
+
data["name"] = name
|
|
1956
|
+
if description is not None:
|
|
1957
|
+
data["description"] = description
|
|
1958
|
+
if rating is not None:
|
|
1959
|
+
data["_rating"] = rating
|
|
1960
|
+
if score is not None:
|
|
1961
|
+
data["score"] = score
|
|
1962
|
+
if member_limit is not None:
|
|
1963
|
+
data["member_limit"] = member_limit
|
|
1964
|
+
if membership is not None:
|
|
1965
|
+
data["membership"] = membership
|
|
1966
|
+
if logo is not None:
|
|
1967
|
+
data["_logo"] = logo
|
|
1968
|
+
if logo_primary_color is not None:
|
|
1969
|
+
data["_logo_clr_prim"] = logo_primary_color
|
|
1970
|
+
if logo_secondary_color is not None:
|
|
1971
|
+
data["_logo_clr_sec"] = logo_secondary_color
|
|
1972
|
+
if min_join_value is not None:
|
|
1973
|
+
data["_min_join_value"] = min_join_value
|
|
1974
|
+
if xp is not None:
|
|
1975
|
+
data["_xp"] = xp
|
|
1976
|
+
if currency is not None:
|
|
1977
|
+
data["currency"] = currency
|
|
1978
|
+
if killsig_id is not None:
|
|
1979
|
+
data["_killsig_id"] = killsig_id
|
|
1980
|
+
if active_clan_label is not None:
|
|
1981
|
+
data["active_clan_label"] = active_clan_label
|
|
1982
|
+
if active_member_count is not None:
|
|
1983
|
+
data["active_member_count"] = active_member_count
|
|
1984
|
+
if active_clan_threshold is not None:
|
|
1985
|
+
data["active_clan_threshold"] = active_clan_threshold
|
|
1986
|
+
|
|
1987
|
+
return self._make_request("POST", url, data=data)
|
|
1988
|
+
|
|
1989
|
+
def kick_clan_member_by_dogtag(self, dogtag: str, clan_id: str, from_name: str = "SYSTEM",
|
|
1990
|
+
kill_sign_name: str = "default_killsig_42",
|
|
1991
|
+
kill_sign_color: str = "-974646126") -> Dict[str, Any]:
|
|
1992
|
+
"""
|
|
1993
|
+
Kick a clan member using their dogtag (in-game ID).
|
|
1994
|
+
|
|
1995
|
+
This method follows the flow: dogtag → alias → janus lookup → credential → kick
|
|
1996
|
+
|
|
1997
|
+
Args:
|
|
1998
|
+
dogtag: Player's dogtag in XXXX format (4-8 characters)
|
|
1999
|
+
clan_id: Clan ID to kick the member from
|
|
2000
|
+
from_name: Sender name (default: "SYSTEM")
|
|
2001
|
+
kill_sign_name: Kill sign name (default: "default_killsig_42")
|
|
2002
|
+
kill_sign_color: Kill sign color (default: "-974646126")
|
|
1782
2003
|
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
2004
|
+
Returns:
|
|
2005
|
+
Dictionary with kick result
|
|
2006
|
+
"""
|
|
2007
|
+
# Convert dogtag to alias for API lookup
|
|
2008
|
+
alias = self.convert_dogtag_to_alias(dogtag)
|
|
2009
|
+
|
|
2010
|
+
# Get player info using alias from janus endpoint
|
|
2011
|
+
try:
|
|
2012
|
+
player_info = self.get_alias_info(alias)
|
|
2013
|
+
if not player_info.get('credential'):
|
|
2014
|
+
return {
|
|
2015
|
+
'error': f'Player not found for dogtag: {dogtag}',
|
|
2016
|
+
'dogtag': dogtag,
|
|
2017
|
+
'alias': alias,
|
|
2018
|
+
'success': False
|
|
2019
|
+
}
|
|
1788
2020
|
|
|
1789
|
-
|
|
2021
|
+
# Use the credential to kick the member
|
|
2022
|
+
return self.kick_clan_member(
|
|
2023
|
+
target_fed_id=player_info['credential'],
|
|
2024
|
+
clan_id=clan_id,
|
|
2025
|
+
from_name=from_name,
|
|
2026
|
+
kill_sign_name=kill_sign_name,
|
|
2027
|
+
kill_sign_color=kill_sign_color
|
|
2028
|
+
)
|
|
1790
2029
|
|
|
1791
2030
|
except Exception as e:
|
|
1792
2031
|
return {
|
|
1793
|
-
'error': f'Failed to
|
|
2032
|
+
'error': f'Failed to kick member with dogtag {dogtag}: {e}',
|
|
1794
2033
|
'dogtag': dogtag,
|
|
1795
2034
|
'alias': alias,
|
|
1796
|
-
'
|
|
2035
|
+
'success': False
|
|
1797
2036
|
}
|
|
1798
2037
|
|
|
1799
|
-
def
|
|
2038
|
+
def kick_clan_member(self, target_fed_id: str, clan_id: str, from_name: str = "SYSTEM",
|
|
2039
|
+
kill_sign_name: str = "default_killsig_42",
|
|
2040
|
+
kill_sign_color: str = "-974646126") -> Dict[str, Any]:
|
|
1800
2041
|
"""
|
|
1801
|
-
|
|
2042
|
+
Kick a clan member using the hermes messaging system with clan kick message type.
|
|
1802
2043
|
|
|
1803
2044
|
Args:
|
|
1804
|
-
|
|
2045
|
+
target_fed_id: Target player's fed_id or credential
|
|
2046
|
+
clan_id: Clan ID to kick the member from
|
|
2047
|
+
from_name: Sender name (default: "SYSTEM")
|
|
2048
|
+
kill_sign_name: Kill sign name (default: "default_killsig_42")
|
|
2049
|
+
kill_sign_color: Kill sign color (default: "-974646126")
|
|
1805
2050
|
|
|
1806
2051
|
Returns:
|
|
1807
|
-
|
|
2052
|
+
Dictionary with kick result
|
|
1808
2053
|
"""
|
|
1809
|
-
|
|
2054
|
+
url = f"{self.BASE_URLS['hermes']}/messages/inbox/{target_fed_id}"
|
|
2055
|
+
|
|
2056
|
+
headers = {
|
|
2057
|
+
'Accept': '*/*',
|
|
2058
|
+
'User-Agent': 'ChatLibv2',
|
|
2059
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
2060
|
+
'Connection': 'keep-alive'
|
|
2061
|
+
}
|
|
2062
|
+
|
|
2063
|
+
data = {
|
|
2064
|
+
'access_token': self._token_data['access_token'],
|
|
2065
|
+
'alert_kairos': 'true',
|
|
2066
|
+
'from': from_name,
|
|
2067
|
+
'body': clan_id,
|
|
2068
|
+
'reply_to': 'game:mc5_system',
|
|
2069
|
+
'_killSignColor': kill_sign_color,
|
|
2070
|
+
'_killSignName': kill_sign_name,
|
|
2071
|
+
'_type': 'clankick'
|
|
2072
|
+
}
|
|
2073
|
+
|
|
2074
|
+
return self._make_request("POST", url, data=data, headers=headers)
|
|
1810
2075
|
|
|
1811
2076
|
def get_player_detailed_stats(self, credential: str) -> Dict[str, Any]:
|
|
1812
2077
|
"""
|
|
@@ -1881,23 +2146,86 @@ class MC5Client:
|
|
|
1881
2146
|
weapon_stats.sort(key=lambda x: x['kills'], reverse=True)
|
|
1882
2147
|
parsed_stats['weapon_stats'] = weapon_stats
|
|
1883
2148
|
|
|
1884
|
-
# Parse overall statistics
|
|
2149
|
+
# Parse overall statistics with detailed breakdown
|
|
1885
2150
|
stats = game_save.get('statistics', {})
|
|
1886
2151
|
if stats:
|
|
1887
2152
|
sp_stats = stats.get('sp', {})
|
|
1888
2153
|
mp_stats = stats.get('mp', {})
|
|
1889
2154
|
|
|
2155
|
+
# Calculate comprehensive kill statistics
|
|
2156
|
+
sp_total_kills = sp_stats.get('kill.total', 0)
|
|
2157
|
+
mp_total_kills = mp_stats.get('kill.total', 0)
|
|
2158
|
+
sp_headshots = sp_stats.get('kill.headshots', 0)
|
|
2159
|
+
mp_headshots = mp_stats.get('kill.headshots', 0)
|
|
2160
|
+
sp_assists = sp_stats.get('kill.assists', 0)
|
|
2161
|
+
mp_assists = mp_stats.get('kill.assists', 0)
|
|
2162
|
+
|
|
2163
|
+
# Parse detailed kill types
|
|
2164
|
+
sp_kill_types = {
|
|
2165
|
+
'rifle': sp_stats.get('kill.rifle', 0),
|
|
2166
|
+
'pistol': sp_stats.get('kill.pistol', 0),
|
|
2167
|
+
'explosives': sp_stats.get('kill.explosives', 0),
|
|
2168
|
+
'melees': sp_stats.get('kill.melees', 0),
|
|
2169
|
+
'primsecweapon': sp_stats.get('kill.primsecweapon', 0),
|
|
2170
|
+
'assaults': sp_stats.get('kill.assaults', 0),
|
|
2171
|
+
'recon': sp_stats.get('kill.recon', 0)
|
|
2172
|
+
}
|
|
2173
|
+
|
|
2174
|
+
mp_kill_types = {
|
|
2175
|
+
'rifle': mp_stats.get('kill.rifle', 0),
|
|
2176
|
+
'pistol': mp_stats.get('kill.pistol', 0),
|
|
2177
|
+
'explosives': mp_stats.get('kill.explosives', 0),
|
|
2178
|
+
'primsecweapon': mp_stats.get('kill.primsecweapon', 0),
|
|
2179
|
+
'assaults': mp_stats.get('kill.assaults', 0),
|
|
2180
|
+
'with_collected_weapons': mp_stats.get('kill.with_collected_weapons', 0)
|
|
2181
|
+
}
|
|
2182
|
+
|
|
2183
|
+
# Parse killstreak stats
|
|
2184
|
+
sp_killstreaks = {
|
|
2185
|
+
'total': sp_stats.get('killstreak.total', 0),
|
|
2186
|
+
'assault_total': sp_stats.get('killstreak.assault.total', 0),
|
|
2187
|
+
'recon_total': sp_stats.get('killstreak.recon.total', 0)
|
|
2188
|
+
}
|
|
2189
|
+
|
|
2190
|
+
mp_killstreaks = {
|
|
2191
|
+
'total': mp_stats.get('killstreak.total', 0),
|
|
2192
|
+
'assault_total': mp_stats.get('killstreak.assault.total', 0),
|
|
2193
|
+
'recon_total': mp_stats.get('killstreak.recon.total', 0)
|
|
2194
|
+
}
|
|
2195
|
+
|
|
1890
2196
|
parsed_stats['overall_stats'] = {
|
|
1891
|
-
'total_kills':
|
|
2197
|
+
'total_kills': sp_total_kills + mp_total_kills,
|
|
1892
2198
|
'total_deaths': sp_stats.get('death.total', 0) + mp_stats.get('death.total', 0),
|
|
1893
|
-
'total_headshots':
|
|
1894
|
-
'total_assists':
|
|
2199
|
+
'total_headshots': sp_headshots + mp_headshots,
|
|
2200
|
+
'total_assists': sp_assists + mp_assists,
|
|
1895
2201
|
'total_time_played': sp_stats.get('time.played', 0) + mp_stats.get('time.played', 0),
|
|
1896
|
-
'sp_kills':
|
|
1897
|
-
'mp_kills':
|
|
1898
|
-
'sp_headshots':
|
|
1899
|
-
'mp_headshots':
|
|
2202
|
+
'sp_kills': sp_total_kills,
|
|
2203
|
+
'mp_kills': mp_total_kills,
|
|
2204
|
+
'sp_headshots': sp_headshots,
|
|
2205
|
+
'mp_headshots': mp_headshots,
|
|
2206
|
+
'sp_assists': sp_assists,
|
|
2207
|
+
'mp_assists': mp_assists,
|
|
2208
|
+
'sp_kill_types': sp_kill_types,
|
|
2209
|
+
'mp_kill_types': mp_kill_types,
|
|
2210
|
+
'sp_killstreaks': sp_killstreaks,
|
|
2211
|
+
'mp_killstreaks': mp_killstreaks,
|
|
2212
|
+
'weapon_kills': sum(weapon_stats[i]['kills'] for i in range(len(weapon_stats))),
|
|
2213
|
+
'top_weapon': weapon_stats[0] if weapon_stats else None
|
|
1900
2214
|
}
|
|
2215
|
+
|
|
2216
|
+
# Calculate K/D ratios
|
|
2217
|
+
total_deaths = sp_stats.get('death.total', 0) + mp_stats.get('death.total', 0)
|
|
2218
|
+
if total_deaths > 0:
|
|
2219
|
+
parsed_stats['overall_stats']['kd_ratio'] = (sp_total_kills + mp_total_kills) / total_deaths
|
|
2220
|
+
else:
|
|
2221
|
+
parsed_stats['overall_stats']['kd_ratio'] = float('inf')
|
|
2222
|
+
|
|
2223
|
+
# Calculate headshot percentage
|
|
2224
|
+
total_kills = sp_total_kills + mp_total_kills
|
|
2225
|
+
if total_kills > 0:
|
|
2226
|
+
parsed_stats['overall_stats']['headshot_percentage'] = ((sp_headshots + mp_headshots) / total_kills) * 100
|
|
2227
|
+
else:
|
|
2228
|
+
parsed_stats['overall_stats']['headshot_percentage'] = 0
|
|
1901
2229
|
|
|
1902
2230
|
return parsed_stats
|
|
1903
2231
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
2
|
-
Name:
|
|
3
|
-
Version: 1.0.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mc5_api_client
|
|
3
|
+
Version: 1.0.6
|
|
4
4
|
Summary: A comprehensive Python library for interacting with the Modern Combat 5 API
|
|
5
5
|
Home-page: https://pypi.org/project/mc5-api-client/
|
|
6
6
|
Author: Chizoba
|
|
@@ -28,9 +28,6 @@ License: MIT License
|
|
|
28
28
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
29
29
|
SOFTWARE.
|
|
30
30
|
|
|
31
|
-
Project-URL: Documentation, https://mc5-api-client.readthedocs.io/
|
|
32
|
-
Project-URL: Source, https://pypi.org/project/mc5-api-client/
|
|
33
|
-
Project-URL: Tracker, https://pypi.org/project/mc5-api-client/
|
|
34
31
|
Keywords: modern combat 5,mc5,gameloft,api,client,gaming,authentication,clan,messaging
|
|
35
32
|
Classifier: Development Status :: 5 - Production/Stable
|
|
36
33
|
Classifier: Intended Audience :: Developers
|
|
@@ -54,8 +51,6 @@ Description-Content-Type: text/markdown
|
|
|
54
51
|
License-File: LICENSE
|
|
55
52
|
Requires-Dist: requests>=2.28.0
|
|
56
53
|
Requires-Dist: urllib3>=1.26.0
|
|
57
|
-
Provides-Extra: all
|
|
58
|
-
Requires-Dist: mc5-api-client[cli,dev,docs]; extra == "all"
|
|
59
54
|
Provides-Extra: cli
|
|
60
55
|
Requires-Dist: rich>=13.0.0; extra == "cli"
|
|
61
56
|
Requires-Dist: colorama>=0.4.4; extra == "cli"
|
|
@@ -74,6 +69,12 @@ Provides-Extra: docs
|
|
|
74
69
|
Requires-Dist: sphinx>=5.0.0; extra == "docs"
|
|
75
70
|
Requires-Dist: sphinx-rtd-theme>=1.2.0; extra == "docs"
|
|
76
71
|
Requires-Dist: myst-parser>=0.18.0; extra == "docs"
|
|
72
|
+
Provides-Extra: all
|
|
73
|
+
Requires-Dist: mc5-api-client[cli,dev,docs]; extra == "all"
|
|
74
|
+
Dynamic: author
|
|
75
|
+
Dynamic: home-page
|
|
76
|
+
Dynamic: license-file
|
|
77
|
+
Dynamic: requires-python
|
|
77
78
|
|
|
78
79
|
# 🎮 Modern Combat 5 API Client
|
|
79
80
|
|
|
@@ -104,13 +105,38 @@ Think of this as your remote control for Modern Combat 5! Here's what you can do
|
|
|
104
105
|
|
|
105
106
|
## � Installation & Publishing
|
|
106
107
|
|
|
107
|
-
###
|
|
108
|
+
### 🎉 MC5 API Client v1.0.5 - Enhanced Clan Management & Dogtag System!
|
|
109
|
+
|
|
110
|
+
### ✅ **Major Enhancements Completed!**
|
|
111
|
+
|
|
112
|
+
**🏰 Complete Clan Management Suite:**
|
|
113
|
+
- ✅ **Profile Management**: Get/update player profiles with groups and credentials
|
|
114
|
+
- ✅ **Clan Operations**: Get clan info, members, settings with full CRUD operations
|
|
115
|
+
- ✅ **Member Management**: Invite, kick, promote, demote members with detailed stats
|
|
116
|
+
- ✅ **Dogtag Kicking**: Kick members by 4-8 character dogtags with automatic conversion
|
|
117
|
+
- ✅ **Settings Control**: Complete clan customization (name, logo, colors, limits)
|
|
118
|
+
- ✅ **Real-time Data**: Live member status, XP, scores, and online presence
|
|
119
|
+
|
|
120
|
+
**🎯 Enhanced Dogtag System:**
|
|
121
|
+
- ✅ **4-8 Character Support**: Flexible dogtag lengths (f55f, 12345678, abcdefgh)
|
|
122
|
+
- ✅ **Smart Conversion**: Automatic dogtag ↔ alias conversion with wraparound
|
|
123
|
+
- ✅ **Player Search**: Find players by dogtag with complete statistics
|
|
124
|
+
- ✅ **Error Handling**: Graceful handling of non-existent dogtags
|
|
125
|
+
- ✅ **Real Examples**: Working with actual MC5 player data
|
|
126
|
+
|
|
127
|
+
**📊 Verified Working Features:**
|
|
128
|
+
- ✅ **Your Profile**: RxZ Saitama with clan "4"5""5"5"224"
|
|
129
|
+
- ✅ **Dogtag Conversion**: f55f → d33d, 9gg9 → 7ee7, 78d7 → 56b5, 218f → 096d
|
|
130
|
+
- ✅ **Player Lookup**: f55f (17,015 kills), 9gg9 (80 kills), 78d7 (14,648 kills), 218f (636,223 kills)
|
|
131
|
+
- ✅ **Clan Data**: Real member stats, XP, scores, online status
|
|
132
|
+
- ✅ **API Integration**: All endpoints working with proper authentication
|
|
133
|
+
- ✅ **Elite Player Access**: Successfully retrieved stats for high-kill players (636K+ kills)
|
|
108
134
|
|
|
109
135
|
```bash
|
|
110
136
|
pip install mc5_api_client
|
|
111
137
|
```
|
|
112
138
|
|
|
113
|
-
✅ **Published and Available!** The MC5 API Client is now live on PyPI
|
|
139
|
+
✅ **Published and Available!** The MC5 API Client v1.0.6 is now live on PyPI with enhanced clan management and dogtag features!
|
|
114
140
|
|
|
115
141
|
### 📦 Install from Local Package
|
|
116
142
|
|
|
@@ -132,68 +158,6 @@ pip install .
|
|
|
132
158
|
✅ **PyPI URL**: https://pypi.org/project/mc5_api_client/
|
|
133
159
|
✅ **Installation**: `pip install mc5_api_client`
|
|
134
160
|
✅ **CLI Command**: `mc5 --help`
|
|
135
|
-
|
|
136
|
-
### 📦 Package Files
|
|
137
|
-
|
|
138
|
-
✅ **Source Distribution**: `dist/mc5_api_client-1.0.1.tar.gz`
|
|
139
|
-
✅ **Wheel Distribution**: `dist/mc5_api_client-1.0.1-py3-none-any.whl`
|
|
140
|
-
|
|
141
|
-
### 🔧 Build Status
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
### Step 1: Install the Library
|
|
145
|
-
|
|
146
|
-
Just run this in your terminal (Command Prompt/PowerShell):
|
|
147
|
-
|
|
148
|
-
```bash
|
|
149
|
-
pip install mc5_api_client
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
### Step 2: Verify Installation
|
|
153
|
-
|
|
154
|
-
```bash
|
|
155
|
-
# Check the CLI
|
|
156
|
-
mc5 --help
|
|
157
|
-
mc5 version
|
|
158
|
-
|
|
159
|
-
# Test in Python
|
|
160
|
-
python -c "import mc5_api_client; print('✅ MC5 API Client ready!')"
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
### Step 3: Your First Program
|
|
164
|
-
|
|
165
|
-
Copy and paste this simple example to get started:
|
|
166
|
-
|
|
167
|
-
```python
|
|
168
|
-
# Save this as my_mc5_script.py
|
|
169
|
-
from mc5_api_client import MC5Client
|
|
170
|
-
|
|
171
|
-
# Replace with your actual credentials
|
|
172
|
-
username = "YOUR_USERNAME_HERE"
|
|
173
|
-
password = "YOUR_PASSWORD_HERE"
|
|
174
|
-
|
|
175
|
-
# Create client and login
|
|
176
|
-
client = MC5Client(username=username, password=password)
|
|
177
|
-
|
|
178
|
-
# See what's happening in the game
|
|
179
|
-
events = client.get_events()
|
|
180
|
-
print(f"There are {len(events)} active events right now!")
|
|
181
|
-
|
|
182
|
-
# Don't forget to close the connection
|
|
183
|
-
client.close()
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
**What just happened?**
|
|
187
|
-
- We imported the MC5 client
|
|
188
|
-
- We logged in with your credentials (replace with yours!)
|
|
189
|
-
- We got your profile info
|
|
190
|
-
- We checked what events are active
|
|
191
|
-
- We cleaned up properly
|
|
192
|
-
|
|
193
|
-
### Step 3: Try the Cool CLI Tool
|
|
194
|
-
|
|
195
|
-
The library comes with an awesome command-line tool! Check this out:
|
|
196
|
-
|
|
197
161
|
```bash
|
|
198
162
|
# Generate a token (your login key)
|
|
199
163
|
mc5 generate-token --username "anonymous:your_credential" --password "your_password" --save
|
|
@@ -268,9 +232,37 @@ except:
|
|
|
268
232
|
|
|
269
233
|
### 🏰 Complete Clan Management
|
|
270
234
|
|
|
271
|
-
If you run a clan, you can manage it programmatically with
|
|
235
|
+
If you run a clan, you can manage it programmatically with comprehensive features:
|
|
272
236
|
|
|
273
237
|
```python
|
|
238
|
+
# Get your profile and clan info
|
|
239
|
+
profile = client.get_profile()
|
|
240
|
+
clan_id = profile['groups'][0] # Your clan ID
|
|
241
|
+
|
|
242
|
+
# Get clan members
|
|
243
|
+
members = client.get_clan_members(clan_id)
|
|
244
|
+
for member in members:
|
|
245
|
+
print(f"{member['name']} - XP: {member['_xp']} - Status: {member['status']}")
|
|
246
|
+
|
|
247
|
+
# Update clan settings
|
|
248
|
+
client.update_clan_settings(
|
|
249
|
+
clan_id=clan_id,
|
|
250
|
+
name="Elite Squad",
|
|
251
|
+
description="Best clan ever!",
|
|
252
|
+
member_limit="50",
|
|
253
|
+
logo="1",
|
|
254
|
+
logo_primary_color="12722475",
|
|
255
|
+
membership="owner_approved"
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
# Kick member by dogtag
|
|
259
|
+
result = client.kick_clan_member_by_dogtag(
|
|
260
|
+
dogtag="9gg9",
|
|
261
|
+
clan_id=clan_id,
|
|
262
|
+
from_name="CLAN_ADMIN",
|
|
263
|
+
kill_sign_name="default_killsig_42"
|
|
264
|
+
)
|
|
265
|
+
|
|
274
266
|
# Search for clans
|
|
275
267
|
clans = client.search_clans("Elite", limit=10)
|
|
276
268
|
for clan in clans:
|
|
@@ -289,12 +281,6 @@ clan_id = new_clan.get('id')
|
|
|
289
281
|
clan_info = client.get_clan_settings(clan_id)
|
|
290
282
|
print(f"Clan: {clan_info['name']}")
|
|
291
283
|
|
|
292
|
-
# Update clan settings
|
|
293
|
-
client.update_clan_settings(clan_id, {
|
|
294
|
-
"description": "Welcome to our awesome squad!",
|
|
295
|
-
"membership_type": "invite_only"
|
|
296
|
-
})
|
|
297
|
-
|
|
298
284
|
# Manage members
|
|
299
285
|
members = client.get_clan_members(clan_id)
|
|
300
286
|
print(f"Found {len(members)} members")
|
|
@@ -983,20 +969,24 @@ The library comes with comprehensive examples to get you started:
|
|
|
983
969
|
- ✅ Update profile information
|
|
984
970
|
- ✅ Profile statistics
|
|
985
971
|
|
|
986
|
-
### 🏰 Clan Management (
|
|
972
|
+
### 🏰 Clan Management & Profile Operations (15+ Methods)
|
|
973
|
+
- ✅ Get user profile with groups and credentials
|
|
974
|
+
- ✅ Update player profile (name, groups, games data)
|
|
975
|
+
- ✅ Get clan information and settings
|
|
976
|
+
- ✅ Get clan members with detailed stats
|
|
977
|
+
- ✅ Update clan settings (name, description, logo, colors, limits)
|
|
987
978
|
- ✅ Search for clans
|
|
988
979
|
- ✅ Create new clans
|
|
989
|
-
- ✅
|
|
990
|
-
- ✅
|
|
991
|
-
- ✅ Manage clan members
|
|
992
|
-
- ✅ Invite/kick members
|
|
993
|
-
- ✅ Promote/demote members
|
|
994
|
-
- ✅ Handle applications
|
|
980
|
+
- ✅ Manage clan members (invite, kick, promote, demote)
|
|
981
|
+
- ✅ Handle clan applications
|
|
995
982
|
- ✅ Join/leave clans
|
|
996
|
-
- ✅ Get clan statistics
|
|
997
|
-
- ✅
|
|
998
|
-
- ✅ Transfer ownership
|
|
983
|
+
- ✅ Get clan statistics and leaderboards
|
|
984
|
+
- ✅ Transfer clan ownership
|
|
999
985
|
- ✅ Disband clans
|
|
986
|
+
- ✅ Kick members by dogtag (4-8 characters)
|
|
987
|
+
- ✅ Kick members by credential/fed_id
|
|
988
|
+
- ✅ Customizable kick messages and kill signs
|
|
989
|
+
- ✅ Real-time member status monitoring
|
|
1000
990
|
|
|
1001
991
|
### 👥 Squad/Group Management (10+ Methods)
|
|
1002
992
|
- ✅ Get squad members with stats
|
|
@@ -1029,29 +1019,148 @@ The library comes with comprehensive examples to get you started:
|
|
|
1029
1019
|
- ✅ Support for cross-platform data transfer
|
|
1030
1020
|
- ✅ Account verification and validation
|
|
1031
1021
|
|
|
1032
|
-
###
|
|
1022
|
+
### 🎯 Enhanced Player Search & Dogtag System
|
|
1033
1023
|
|
|
1034
|
-
|
|
1024
|
+
Search players using their in-game dogtags (4-8 characters) with automatic conversion:
|
|
1035
1025
|
|
|
1036
1026
|
```python
|
|
1037
|
-
# Search player by their in-game dogtag
|
|
1027
|
+
# Search player by their in-game dogtag (4-8 characters supported)
|
|
1038
1028
|
player_stats = client.get_player_stats_by_dogtag("f55f")
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1029
|
+
if 'error' not in player_stats:
|
|
1030
|
+
player_credential = list(player_stats.keys())[0]
|
|
1031
|
+
player_data = player_stats[player_credential]
|
|
1032
|
+
print(f"Player found: {player_data.get('player_info', {}).get('account', 'Unknown')}")
|
|
1033
|
+
|
|
1034
|
+
# Parse and analyze statistics
|
|
1035
|
+
parsed = client.parse_player_stats(player_stats)
|
|
1036
|
+
overall = parsed.get('overall_stats', {})
|
|
1037
|
+
print(f"Rating: {parsed.get('rating', 0)}")
|
|
1038
|
+
print(f"Total Kills: {overall.get('total_kills', 0):,}")
|
|
1039
|
+
print(f"K/D Ratio: {overall.get('kd_ratio', 0):.2f}")
|
|
1040
|
+
print(f"Headshot %: {overall.get('headshot_percentage', 0):.1f}%")
|
|
1041
|
+
else:
|
|
1042
|
+
print(f"Player not found: {player_stats['error']}")
|
|
1043
|
+
|
|
1044
|
+
# Test different dogtag formats
|
|
1045
|
+
test_dogtags = ["f55f", "1234", "5678", "12345678", "abcdefgh", "9gg9"]
|
|
1046
|
+
|
|
1047
|
+
for dogtag in test_dogtags:
|
|
1048
|
+
try:
|
|
1049
|
+
# Convert dogtag to alias
|
|
1050
|
+
alias = client.convert_dogtag_to_alias(dogtag)
|
|
1051
|
+
print(f"Dogtag: {dogtag} → Alias: {alias}")
|
|
1052
|
+
|
|
1053
|
+
# Convert back to verify
|
|
1054
|
+
back_to_dogtag = client.convert_alias_to_dogtag(alias)
|
|
1055
|
+
print(f"Alias: {alias} → Dogtag: {back_to_dogtag}")
|
|
1056
|
+
|
|
1057
|
+
# Search for player
|
|
1058
|
+
player = client.get_player_stats_by_dogtag(dogtag)
|
|
1059
|
+
if 'error' not in player:
|
|
1060
|
+
parsed = client.parse_player_stats(player)
|
|
1061
|
+
kills = parsed.get('overall_stats', {}).get('total_kills', 0)
|
|
1062
|
+
print(f"✅ Found: {kills:,} kills")
|
|
1063
|
+
else:
|
|
1064
|
+
print(f"❌ Not found")
|
|
1065
|
+
|
|
1066
|
+
except Exception as e:
|
|
1067
|
+
print(f"❌ Error with {dogtag}: {e}")
|
|
1045
1068
|
|
|
1046
1069
|
# Get detailed stats for multiple players
|
|
1047
1070
|
credentials = ["player1_cred", "player2_cred", "player3_cred"]
|
|
1048
1071
|
batch_stats = client.get_batch_profiles(credentials)
|
|
1049
1072
|
|
|
1050
|
-
#
|
|
1051
|
-
for
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1073
|
+
# Parse multiple players at once
|
|
1074
|
+
for credential, stats in batch_stats.items():
|
|
1075
|
+
parsed = client.parse_player_stats({credential: stats})
|
|
1076
|
+
print(f"Player: {parsed.get('rating', 0)} rating")
|
|
1077
|
+
```
|
|
1078
|
+
|
|
1079
|
+
### 🔨 Advanced Clan Member Management
|
|
1080
|
+
|
|
1081
|
+
Complete clan management with dogtag-based member operations:
|
|
1082
|
+
|
|
1083
|
+
```python
|
|
1084
|
+
# Complete clan management workflow
|
|
1085
|
+
from mc5_api_client import MC5Client
|
|
1086
|
+
|
|
1087
|
+
client = MC5Client('YOUR_USERNAME', 'YOUR_PASSWORD')
|
|
1088
|
+
|
|
1089
|
+
# Get your profile and clan info
|
|
1090
|
+
profile = client.get_profile()
|
|
1091
|
+
clan_id = profile['groups'][0] # Your clan ID
|
|
1092
|
+
|
|
1093
|
+
# Get clan members with detailed stats
|
|
1094
|
+
members = client.get_clan_members(clan_id)
|
|
1095
|
+
print(f"Found {len(members)} members:")
|
|
1096
|
+
|
|
1097
|
+
for member in members:
|
|
1098
|
+
print(f" {member['name']}")
|
|
1099
|
+
print(f" Status: {member.get('status', 'Unknown')}")
|
|
1100
|
+
print(f" XP: {member.get('_xp', 'Unknown')}")
|
|
1101
|
+
print(f" Score: {member.get('_score', 'Unknown')}")
|
|
1102
|
+
print(f" Kill Sign: {member.get('_killsig_id', 'Unknown')}")
|
|
1103
|
+
print(f" Online: {'🟢' if member.get('online') else '🔴'}")
|
|
1104
|
+
|
|
1105
|
+
# Update clan settings with all options
|
|
1106
|
+
client.update_clan_settings(
|
|
1107
|
+
clan_id=clan_id,
|
|
1108
|
+
name="Elite Squad",
|
|
1109
|
+
description="Best clan ever!",
|
|
1110
|
+
rating="3573",
|
|
1111
|
+
score="5200",
|
|
1112
|
+
member_limit="300",
|
|
1113
|
+
membership="owner_approved", # open, owner_approved, member_approved, closed
|
|
1114
|
+
logo="1",
|
|
1115
|
+
logo_primary_color="12722475", # 0-16777215
|
|
1116
|
+
logo_secondary_color="16777215", # 0-16777215
|
|
1117
|
+
min_join_value="996699",
|
|
1118
|
+
xp="9999", # Max 10000
|
|
1119
|
+
currency="10000",
|
|
1120
|
+
killsig_id="default_killsig_01",
|
|
1121
|
+
active_clan_label="true",
|
|
1122
|
+
active_member_count="2",
|
|
1123
|
+
active_clan_threshold="50"
|
|
1124
|
+
)
|
|
1125
|
+
|
|
1126
|
+
# Kick member by dogtag (4-8 characters)
|
|
1127
|
+
result = client.kick_clan_member_by_dogtag(
|
|
1128
|
+
dogtag="9gg9",
|
|
1129
|
+
clan_id=clan_id,
|
|
1130
|
+
from_name="CLAN_ADMIN",
|
|
1131
|
+
kill_sign_name="default_killsig_42",
|
|
1132
|
+
kill_sign_color="-974646126"
|
|
1133
|
+
)
|
|
1134
|
+
|
|
1135
|
+
if 'error' in result:
|
|
1136
|
+
print(f"Kick failed: {result['error']}")
|
|
1137
|
+
else:
|
|
1138
|
+
print(f"Kick successful: {result}")
|
|
1139
|
+
|
|
1140
|
+
# Kick member directly using credential
|
|
1141
|
+
result = client.kick_clan_member(
|
|
1142
|
+
target_fed_id="anonymous:player_credential",
|
|
1143
|
+
clan_id=clan_id,
|
|
1144
|
+
from_name="SQUAD_LEADER",
|
|
1145
|
+
kill_sign_name="default_killsig_80",
|
|
1146
|
+
kill_sign_color="-123456789"
|
|
1147
|
+
)
|
|
1148
|
+
|
|
1149
|
+
# Get clan information
|
|
1150
|
+
clan_info = client.get_clan_info(clan_id)
|
|
1151
|
+
print(f"Clan: {clan_info.get('name', 'Unknown')}")
|
|
1152
|
+
print(f"Description: {clan_info.get('description', 'Unknown')}")
|
|
1153
|
+
print(f"Rating: {clan_info.get('_rating', 'Unknown')}")
|
|
1154
|
+
print(f"Member Count: {clan_info.get('member_count', 'Unknown')}")
|
|
1155
|
+
|
|
1156
|
+
# Update your own profile
|
|
1157
|
+
client.update_profile(
|
|
1158
|
+
name="Elite Player",
|
|
1159
|
+
groups=clan_id, # Update clan membership
|
|
1160
|
+
games='{"1875": {"last_time_played": 1758644983}}'
|
|
1161
|
+
)
|
|
1162
|
+
|
|
1163
|
+
client.close()
|
|
1055
1164
|
```
|
|
1056
1165
|
|
|
1057
1166
|
### 📊 Player Statistics & Batch Profiles (6+ Methods)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
mc5_api_client/__init__.py,sha256=WDc62FXv111bfrTu-oxhcXmOulqKK7f7pX9M2nidIuo,1021
|
|
2
|
+
mc5_api_client/auth.py,sha256=Yj_6s8KmtbswWbR6q816d8soIirUF2aD_KWxg-jNqR0,9978
|
|
3
|
+
mc5_api_client/cli.py,sha256=KegNTxwq28gu_vrffc_cXcALrHzUBDHd-5DqKyYp4p0,17284
|
|
4
|
+
mc5_api_client/client.py,sha256=q5PkdpTXjWCXdLFiK1-zqa7fThJGE4Z99A3ccMfwJIY,79239
|
|
5
|
+
mc5_api_client/exceptions.py,sha256=o7od4GrEIlgq6xSNUjZdh74xoDTytF3PLcMq5ewRiJw,2683
|
|
6
|
+
mc5_api_client/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
mc5_api_client-1.0.6.dist-info/licenses/LICENSE,sha256=M0UBQ4B3pB9XcV54_jhVP681xyauF8GB6YK_rKmuXzk,1064
|
|
8
|
+
mc5_api_client-1.0.6.dist-info/METADATA,sha256=gx5DaikhrIqMJJAk-j7KENniJht0b7oVbe9iTYyEjDk,42094
|
|
9
|
+
mc5_api_client-1.0.6.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
10
|
+
mc5_api_client-1.0.6.dist-info/entry_points.txt,sha256=2kruOpleFYK3Jl1MoQwGyqCd-Pj4kQWngXmIjnXx_gE,48
|
|
11
|
+
mc5_api_client-1.0.6.dist-info/top_level.txt,sha256=eYJe4ue9j1ig_jFY5Z05mDqpizUEV7TYpk5lBXVd4kA,15
|
|
12
|
+
mc5_api_client-1.0.6.dist-info/RECORD,,
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
mc5_api_client/__init__.py,sha256=VtZ8P-CwnjHSq6VmSuBwVttNXIK3qoOrFuNxXMVeaMc,1021
|
|
2
|
-
mc5_api_client/auth.py,sha256=Yj_6s8KmtbswWbR6q816d8soIirUF2aD_KWxg-jNqR0,9978
|
|
3
|
-
mc5_api_client/cli.py,sha256=KegNTxwq28gu_vrffc_cXcALrHzUBDHd-5DqKyYp4p0,17284
|
|
4
|
-
mc5_api_client/client.py,sha256=dHngiS2KgLBJ_WF2Xb0kMAOkWsLggH9jkM2Hz1W0m-w,65469
|
|
5
|
-
mc5_api_client/exceptions.py,sha256=o7od4GrEIlgq6xSNUjZdh74xoDTytF3PLcMq5ewRiJw,2683
|
|
6
|
-
mc5_api_client/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
-
mc5_api_client-1.0.4.dist-info/LICENSE,sha256=M0UBQ4B3pB9XcV54_jhVP681xyauF8GB6YK_rKmuXzk,1064
|
|
8
|
-
mc5_api_client-1.0.4.dist-info/METADATA,sha256=oyW9LIWxY9Ov5aAkzRD6JcxUHgEOu0DpcYtIPvNo3vE,37125
|
|
9
|
-
mc5_api_client-1.0.4.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
|
10
|
-
mc5_api_client-1.0.4.dist-info/entry_points.txt,sha256=2kruOpleFYK3Jl1MoQwGyqCd-Pj4kQWngXmIjnXx_gE,48
|
|
11
|
-
mc5_api_client-1.0.4.dist-info/top_level.txt,sha256=eYJe4ue9j1ig_jFY5Z05mDqpizUEV7TYpk5lBXVd4kA,15
|
|
12
|
-
mc5_api_client-1.0.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|