mc5-api-client 1.0.17__py3-none-any.whl → 1.0.19__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.
@@ -15,7 +15,7 @@ messaging, and more.
15
15
 
16
16
  from typing import Optional, Dict, Any
17
17
 
18
- __version__ = "1.0.16"
18
+ __version__ = "1.0.19"
19
19
  __author__ = "Chizoba"
20
20
  __email__ = "chizoba2026@hotmail.com"
21
21
  __license__ = "MIT"
@@ -87,6 +87,9 @@ from .client import MC5Client
87
87
  from .auth import TokenGenerator
88
88
  from .exceptions import MC5APIError, AuthenticationError, RateLimitError
89
89
  from .help import help, examples, quick_reference
90
+
91
+ # Add MC5ApiClient as an alias for backward compatibility
92
+ MC5ApiClient = MC5Client
90
93
  from .admin_client import (
91
94
  AdminMC5Client,
92
95
  create_admin_client,
@@ -94,11 +97,185 @@ from .admin_client import (
94
97
  quick_add_squad_rating,
95
98
  quick_update_player_score
96
99
  )
100
+ from .pc_storage_client import PCStorageClient
101
+ from .storage_admin import StorageAdminMixin
102
+ from .easy_mc5 import MC5Easy
97
103
 
98
104
  # Encrypted token convenience functions
99
105
  from .auth import TokenGenerator
100
106
 
101
- def quick_generate_encrypted_token(
107
+ # Convenience functions for global ID operations
108
+ def get_global_id(device_id: str = None, device_type: str = "w10", hdidfv: str = None) -> str:
109
+ """
110
+ Get a global device ID from Gameloft's global ID service.
111
+
112
+ Args:
113
+ device_id: Your device ID (optional, will generate one if not provided)
114
+ device_type: Device type (w10, android, ios, etc.)
115
+ hdidfv: Hardware ID fingerprint (optional)
116
+
117
+ Returns:
118
+ Global device ID string
119
+ """
120
+ import requests
121
+
122
+ # Build request parameters
123
+ params = {
124
+ "source": "Identifiers_6.0.0",
125
+ "client_id": "1875:55979:6.0.0a:windows:windows",
126
+ "device_type": device_type,
127
+ "global_device_id": device_id or "1364509832654538259",
128
+ "hdidfv": hdidfv or "76dfc72e-7850-4d9e-b79c-9861c7e3ea20"
129
+ }
130
+
131
+ headers = {
132
+ "Accept": "*/*",
133
+ "Accept-Encoding": "gzip;q=1.0, deflate;q=1.0, identity;q=0.5, *;q=0"
134
+ }
135
+
136
+ try:
137
+ response = requests.get(
138
+ "https://gdid.datalake.gameloft.com/assign_global_id/",
139
+ params=params,
140
+ headers=headers,
141
+ timeout=30
142
+ )
143
+
144
+ if response.status_code == 200:
145
+ return response.text.strip()
146
+ else:
147
+ return ""
148
+ except Exception:
149
+ return ""
150
+
151
+ def generate_device_id() -> str:
152
+ """
153
+ Generate a unique device ID for the current device.
154
+
155
+ Returns:
156
+ Generated device ID string
157
+ """
158
+ import uuid
159
+
160
+ # Generate a unique device ID
161
+ device_id = f"mc5_{uuid.uuid4().hex[:16]}"
162
+ return device_id
163
+
164
+ def create_federation_session(username: str = None, password: str = None, device_id: str = None) -> Dict[str, Any]:
165
+ """
166
+ Create a federation session for MC5 game launch.
167
+
168
+ Args:
169
+ username: MC5 username (can use MC5_USERNAME env var)
170
+ password: MC5 password (can use MC5_PASSWORD env var)
171
+ device_id: Device ID for the session (optional)
172
+
173
+ Returns:
174
+ Dictionary with session information
175
+ """
176
+ import os
177
+ import requests
178
+
179
+ # Use environment variables if not provided
180
+ username = username or os.getenv('MC5_USERNAME')
181
+ password = password or os.getenv('MC5_PASSWORD')
182
+
183
+ if not username or not password:
184
+ return {"error": "Username and password are required"}
185
+
186
+ try:
187
+ # Build request parameters
188
+ params = {
189
+ "password": password,
190
+ "device_id": device_id or "1364509832654538259"
191
+ }
192
+
193
+ headers = {
194
+ "Accept": "*/*",
195
+ "Content-Type": "application/x-www-form-urlencoded"
196
+ }
197
+
198
+ # Build URL with encoded credential
199
+ encoded_credential = username.replace(":", "%3A")
200
+ url = f"https://federation-eur.gameloft.com/sessions/1875%3A55979%3A6.0.0a%3Awindows%3Awindows/{encoded_credential}"
201
+
202
+ # Make request
203
+ response = requests.post(
204
+ url,
205
+ data=params,
206
+ headers=headers,
207
+ timeout=30
208
+ )
209
+
210
+ if response.status_code == 200:
211
+ return response.json()
212
+ else:
213
+ return {"error": f"HTTP {response.status_code}", "response": response.text}
214
+
215
+ except Exception as e:
216
+ return {"error": str(e)}
217
+
218
+ def locate_service(service: str) -> str:
219
+ """
220
+ Locate a service endpoint for MC5.
221
+
222
+ Args:
223
+ service: Service name (leaderboard, matchmaker, auth, social, alert, message, lobby, gs, sp)
224
+
225
+ Returns:
226
+ Service endpoint URL or empty string if not found
227
+ """
228
+ import requests
229
+
230
+ try:
231
+ # Build request parameters
232
+ params = {
233
+ "service": service,
234
+ "client_id": "1875:55979:6.0.0a:windows:windows"
235
+ }
236
+
237
+ headers = {
238
+ "Accept": "*/*"
239
+ }
240
+
241
+ # Make request
242
+ response = requests.get(
243
+ "https://vgold-eur.gameloft.com/1875:55979:6.0.0a:windows:windows/locate",
244
+ params=params,
245
+ headers=headers,
246
+ timeout=30
247
+ )
248
+
249
+ if response.status_code == 200:
250
+ return response.text.strip()
251
+ else:
252
+ return ""
253
+
254
+ except Exception:
255
+ return ""
256
+
257
+ def get_all_services() -> Dict[str, str]:
258
+ """
259
+ Get all available service endpoints.
260
+
261
+ Returns:
262
+ Dictionary mapping service names to endpoints
263
+ """
264
+ services = [
265
+ "leaderboard", "matchmaker", "auth", "social",
266
+ "alert", "message", "lobby", "gs", "sp"
267
+ ]
268
+
269
+ service_endpoints = {}
270
+
271
+ for service in services:
272
+ endpoint = locate_service(service)
273
+ if endpoint:
274
+ service_endpoints[service] = endpoint
275
+
276
+ return service_endpoints
277
+
278
+ def generate_encrypted_token(
102
279
  username: str,
103
280
  password: str,
104
281
  device_id: Optional[str] = None,
@@ -106,7 +283,7 @@ def quick_generate_encrypted_token(
106
283
  nonce: str = "*"
107
284
  ) -> Dict[str, Any]:
108
285
  """
109
- Quick function to generate and encrypt an access token.
286
+ Generate and encrypt an access token.
110
287
 
111
288
  Args:
112
289
  username: MC5 username
@@ -125,12 +302,12 @@ def quick_generate_encrypted_token(
125
302
  finally:
126
303
  token_gen.close()
127
304
 
128
- def quick_encrypt_token(
305
+ def encrypt_token(
129
306
  access_token: str,
130
307
  nonce: str = "*"
131
308
  ) -> str:
132
309
  """
133
- Quick function to encrypt an existing access token.
310
+ Encrypt an existing access token.
134
311
 
135
312
  Args:
136
313
  access_token: Raw access token string
@@ -148,6 +325,7 @@ def quick_encrypt_token(
148
325
 
149
326
  __all__ = [
150
327
  "MC5Client",
328
+ "MC5ApiClient",
151
329
  "SimpleMC5Client",
152
330
  "AdminMC5Client",
153
331
  "batch_search_players",
@@ -216,6 +394,16 @@ __all__ = [
216
394
  "help",
217
395
  "examples",
218
396
  "quick_reference",
219
- "quick_generate_encrypted_token",
220
- "quick_encrypt_token"
397
+ "generate_encrypted_token",
398
+ "encrypt_token",
399
+ "MC5Easy",
400
+ "quick_connect",
401
+ "check_my_daily_tasks",
402
+ "get_my_mc5_profile",
403
+ "find_mc5_player",
404
+ "get_global_id",
405
+ "generate_device_id",
406
+ "create_federation_session",
407
+ "locate_service",
408
+ "get_all_services"
221
409
  ]
mc5_api_client/client.py CHANGED
@@ -27,6 +27,7 @@ from .alerts import AlertsMixin
27
27
  from .account import AccountMixin
28
28
  from .transfer import TransferMixin
29
29
  from .platform import Platform, get_platform_config, detect_platform_from_client_id
30
+ from .storage_admin import StorageAdminMixin
30
31
  from .exceptions import (
31
32
  MC5APIError,
32
33
  AuthenticationError,
@@ -37,7 +38,7 @@ from .exceptions import (
37
38
  )
38
39
 
39
40
 
40
- class MC5Client(SquadBattleMixin, FederationMixin, AlertsMixin, AccountMixin, TransferMixin):
41
+ class MC5Client(SquadBattleMixin, FederationMixin, AlertsMixin, AccountMixin, TransferMixin, StorageAdminMixin):
41
42
  """
42
43
  Comprehensive MC5 API client with support for all major endpoints.
43
44
  """
@@ -1572,31 +1573,84 @@ class MC5Client(SquadBattleMixin, FederationMixin, AlertsMixin, AccountMixin, Tr
1572
1573
 
1573
1574
  # Utility Methods
1574
1575
 
1575
- def get_token_info(self) -> Dict[str, Any]:
1576
+ def close(self):
1577
+ """Close the HTTP session and cleanup resources."""
1578
+ if self.session:
1579
+ self.session.close()
1580
+ if self.token_generator:
1581
+ self.token_generator.close()
1582
+
1583
+ # Server Status Methods (for compatibility)
1584
+
1585
+ def get_server_status(self) -> Dict[str, Any]:
1576
1586
  """
1577
- Get current token information.
1587
+ Get server status information.
1578
1588
 
1579
1589
  Returns:
1580
- Token data
1590
+ Dictionary with server status
1581
1591
  """
1582
- self._ensure_valid_token()
1583
- return self._token_data.copy()
1592
+ try:
1593
+ # Try to get events as a basic connectivity test
1594
+ events = self.get_events()
1595
+ return {
1596
+ "status": "online",
1597
+ "message": "MC5 servers are online",
1598
+ "events_count": len(events),
1599
+ "timestamp": time.time()
1600
+ }
1601
+ except Exception as e:
1602
+ return {
1603
+ "status": "offline",
1604
+ "message": f"Server status check failed: {str(e)}",
1605
+ "timestamp": time.time()
1606
+ }
1584
1607
 
1585
- def is_authenticated(self) -> bool:
1608
+ def get_online_players(self) -> Dict[str, Any]:
1586
1609
  """
1587
- Check if client is authenticated with valid token.
1610
+ Get online players information (estimated).
1588
1611
 
1589
1612
  Returns:
1590
- True if authenticated, False otherwise
1613
+ Dictionary with online player count
1591
1614
  """
1592
- return self._token_data is not None and self.token_generator.validate_token(self._token_data)
1615
+ try:
1616
+ # Get events as a proxy for activity
1617
+ events = self.get_events()
1618
+ # This is an estimate - actual player count isn't directly available
1619
+ return {
1620
+ "online_players": "Unknown",
1621
+ "active_events": len(events),
1622
+ "message": "Player count not directly available via API",
1623
+ "timestamp": time.time()
1624
+ }
1625
+ except Exception as e:
1626
+ return {
1627
+ "online_players": 0,
1628
+ "error": str(e),
1629
+ "timestamp": time.time()
1630
+ }
1593
1631
 
1594
- def close(self):
1595
- """Close the HTTP session and cleanup resources."""
1596
- if self.session:
1597
- self.session.close()
1598
- if self.token_generator:
1599
- self.token_generator.close()
1632
+ def get_server_info(self) -> Dict[str, Any]:
1633
+ """
1634
+ Get general server information.
1635
+
1636
+ Returns:
1637
+ Dictionary with server information
1638
+ """
1639
+ try:
1640
+ return {
1641
+ "server": "Modern Combat 5",
1642
+ "region": "Europe",
1643
+ "api_version": "1.0.18",
1644
+ "endpoints": list(self.BASE_URLS.keys()),
1645
+ "client_id": self.client_id,
1646
+ "authenticated": bool(self.access_token),
1647
+ "timestamp": time.time()
1648
+ }
1649
+ except Exception as e:
1650
+ return {
1651
+ "error": str(e),
1652
+ "timestamp": time.time()
1653
+ }
1600
1654
 
1601
1655
  # Events API
1602
1656
 
@@ -2271,6 +2325,28 @@ class MC5Client(SquadBattleMixin, FederationMixin, AlertsMixin, AccountMixin, Tr
2271
2325
  response = self._make_request("GET", url, params=params)
2272
2326
  return response if isinstance(response, list) else []
2273
2327
 
2328
+ def get_squad_members(self, squad_id: str, offset: int = 0, limit: int = 100) -> Dict[str, Any]:
2329
+ """
2330
+ Get squad members list.
2331
+
2332
+ Args:
2333
+ squad_id: Squad ID
2334
+ offset: Offset for pagination
2335
+ limit: Number of members to retrieve
2336
+
2337
+ Returns:
2338
+ Squad members list
2339
+ """
2340
+ url = f"{self.BASE_URLS['osiris']}/groups/{squad_id}/members"
2341
+ params = {
2342
+ "access_token": self._token_data['access_token'],
2343
+ "group_id": squad_id,
2344
+ "offset": str(offset),
2345
+ "limit": str(limit)
2346
+ }
2347
+
2348
+ return self._make_request("GET", url, params=params)
2349
+
2274
2350
  def get_clan_info(self, clan_id: str) -> Dict[str, Any]:
2275
2351
  """
2276
2352
  Get detailed information about a clan.