mc5-api-client 1.0.5__py3-none-any.whl → 1.0.8__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 +19 -1
- mc5_api_client/client.py +406 -79
- mc5_api_client/simple_client.py +570 -0
- {mc5_api_client-1.0.5.dist-info → mc5_api_client-1.0.8.dist-info}/METADATA +349 -41
- mc5_api_client-1.0.8.dist-info/RECORD +13 -0
- {mc5_api_client-1.0.5.dist-info → mc5_api_client-1.0.8.dist-info}/WHEEL +1 -1
- mc5_api_client-1.0.5.dist-info/RECORD +0 -12
- {mc5_api_client-1.0.5.dist-info → mc5_api_client-1.0.8.dist-info}/entry_points.txt +0 -0
- {mc5_api_client-1.0.5.dist-info → mc5_api_client-1.0.8.dist-info/licenses}/LICENSE +0 -0
- {mc5_api_client-1.0.5.dist-info → mc5_api_client-1.0.8.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# ────────────[ CHIZOBA ]────────────────────────────
|
|
3
|
+
# | Email : chizoba2026@hotmail.com
|
|
4
|
+
# | File : simple_client.py
|
|
5
|
+
# | License | MIT License © 2026 Chizoba
|
|
6
|
+
# | Brief : User-friendly MC5 API client for non-developers
|
|
7
|
+
# ────────────────★─────────────────────────────────
|
|
8
|
+
|
|
9
|
+
"""
|
|
10
|
+
MC5 Simple API Client - User Friendly Interface
|
|
11
|
+
|
|
12
|
+
A simplified version of the MC5 API Client designed for non-developers.
|
|
13
|
+
Provides easy-to-use methods with automatic clan detection and simplified syntax.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from typing import Optional, Dict, Any, List
|
|
17
|
+
from .client import MC5Client
|
|
18
|
+
from .exceptions import MC5APIError
|
|
19
|
+
|
|
20
|
+
class SimpleMC5Client:
|
|
21
|
+
"""
|
|
22
|
+
User-friendly MC5 API client for non-developers.
|
|
23
|
+
|
|
24
|
+
Automatically handles clan detection and provides simplified methods
|
|
25
|
+
for common operations.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(self, username: str, password: str):
|
|
29
|
+
"""
|
|
30
|
+
Initialize the client with your MC5 credentials.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
username: Your MC5 username (e.g., "anonymous:your_credential")
|
|
34
|
+
password: Your MC5 password
|
|
35
|
+
"""
|
|
36
|
+
self.username = username
|
|
37
|
+
self.password = password
|
|
38
|
+
self.client = None
|
|
39
|
+
self._clan_id = None
|
|
40
|
+
self._profile = None
|
|
41
|
+
|
|
42
|
+
def connect(self) -> bool:
|
|
43
|
+
"""
|
|
44
|
+
Connect to MC5 and auto-detect your clan.
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
True if connection successful, False otherwise
|
|
48
|
+
"""
|
|
49
|
+
try:
|
|
50
|
+
# Create the client only when connecting
|
|
51
|
+
self.client = MC5Client(self.username, self.password)
|
|
52
|
+
|
|
53
|
+
# Get profile info
|
|
54
|
+
self._profile = self.client.get_profile()
|
|
55
|
+
|
|
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
|
|
65
|
+
|
|
66
|
+
except Exception as e:
|
|
67
|
+
print(f"❌ Connection failed: {e}")
|
|
68
|
+
return False
|
|
69
|
+
|
|
70
|
+
def _get_clan_name(self) -> str:
|
|
71
|
+
"""Get the clan name if available."""
|
|
72
|
+
if not self._clan_id:
|
|
73
|
+
return "No clan"
|
|
74
|
+
|
|
75
|
+
try:
|
|
76
|
+
clan_info = self.client.get_clan_info(self._clan_id)
|
|
77
|
+
return clan_info.get('name', 'Unknown clan')
|
|
78
|
+
except:
|
|
79
|
+
return "Unknown clan"
|
|
80
|
+
|
|
81
|
+
def search_player(self, dogtag: str) -> Optional[Dict[str, Any]]:
|
|
82
|
+
"""
|
|
83
|
+
Search for a player by their dogtag.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
dogtag: Player's dogtag (4-8 characters)
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
Player information or None if not found
|
|
90
|
+
"""
|
|
91
|
+
try:
|
|
92
|
+
stats = self.client.get_player_stats_by_dogtag(dogtag)
|
|
93
|
+
if 'error' not in stats:
|
|
94
|
+
# Parse and return simplified info
|
|
95
|
+
player_credential = list(stats.keys())[0]
|
|
96
|
+
player_data = stats[player_credential]
|
|
97
|
+
parsed = self.client.parse_player_stats(stats)
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
'dogtag': dogtag,
|
|
101
|
+
'account': player_data.get('player_info', {}).get('account', 'Unknown'),
|
|
102
|
+
'rating': parsed.get('rating', 0),
|
|
103
|
+
'kills': parsed.get('overall_stats', {}).get('total_kills', 0),
|
|
104
|
+
'deaths': parsed.get('overall_stats', {}).get('total_deaths', 0),
|
|
105
|
+
'kd_ratio': parsed.get('overall_stats', {}).get('kd_ratio', 0),
|
|
106
|
+
'headshot_percent': parsed.get('overall_stats', {}).get('headshot_percentage', 0),
|
|
107
|
+
'play_time': parsed.get('overall_stats', {}).get('play_time', 0)
|
|
108
|
+
}
|
|
109
|
+
else:
|
|
110
|
+
print(f"❌ Player not found: {stats['error']}")
|
|
111
|
+
return None
|
|
112
|
+
|
|
113
|
+
except Exception as e:
|
|
114
|
+
print(f"❌ Error searching player: {e}")
|
|
115
|
+
return None
|
|
116
|
+
|
|
117
|
+
def get_my_stats(self) -> Optional[Dict[str, Any]]:
|
|
118
|
+
"""
|
|
119
|
+
Get your own player statistics.
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
Your player information or None if error
|
|
123
|
+
"""
|
|
124
|
+
if not self._profile:
|
|
125
|
+
print("❌ Not connected. Call connect() first.")
|
|
126
|
+
return None
|
|
127
|
+
|
|
128
|
+
try:
|
|
129
|
+
return {
|
|
130
|
+
'name': self._profile.get('name', 'Unknown'),
|
|
131
|
+
'level': self._profile.get('level', 0),
|
|
132
|
+
'xp': self._profile.get('xp', 0),
|
|
133
|
+
'clan': self._get_clan_name(),
|
|
134
|
+
'clan_id': self._clan_id
|
|
135
|
+
}
|
|
136
|
+
except Exception as e:
|
|
137
|
+
print(f"❌ Error getting your stats: {e}")
|
|
138
|
+
return None
|
|
139
|
+
|
|
140
|
+
def get_clan_members(self) -> List[Dict[str, Any]]:
|
|
141
|
+
"""
|
|
142
|
+
Get all members of your clan.
|
|
143
|
+
|
|
144
|
+
Returns:
|
|
145
|
+
List of clan members with their stats
|
|
146
|
+
"""
|
|
147
|
+
if not self._clan_id:
|
|
148
|
+
print("❌ No clan detected")
|
|
149
|
+
return []
|
|
150
|
+
|
|
151
|
+
try:
|
|
152
|
+
members = self.client.get_clan_members(self._clan_id)
|
|
153
|
+
|
|
154
|
+
simplified_members = []
|
|
155
|
+
for member in members:
|
|
156
|
+
simplified_members.append({
|
|
157
|
+
'name': member.get('name', 'Unknown'),
|
|
158
|
+
'level': member.get('level', 0),
|
|
159
|
+
'xp': member.get('_xp', 0),
|
|
160
|
+
'score': member.get('_score', 0),
|
|
161
|
+
'status': member.get('status', 'Unknown'),
|
|
162
|
+
'online': member.get('online', False),
|
|
163
|
+
'killsig': member.get('_killsig_id', 'default')
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
return simplified_members
|
|
167
|
+
|
|
168
|
+
except Exception as e:
|
|
169
|
+
print(f"❌ Error getting clan members: {e}")
|
|
170
|
+
return []
|
|
171
|
+
|
|
172
|
+
def kick_member(self, dogtag: str, reason: str = "Kicked from clan") -> bool:
|
|
173
|
+
"""
|
|
174
|
+
Kick a member from your clan by their dogtag.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
dogtag: Member's dogtag to kick
|
|
178
|
+
reason: Reason for kicking (optional)
|
|
179
|
+
|
|
180
|
+
Returns:
|
|
181
|
+
True if successful, False otherwise
|
|
182
|
+
"""
|
|
183
|
+
if not self._clan_id:
|
|
184
|
+
print("❌ No clan detected")
|
|
185
|
+
return False
|
|
186
|
+
|
|
187
|
+
try:
|
|
188
|
+
result = self.client.kick_clan_member_by_dogtag(
|
|
189
|
+
dogtag=dogtag,
|
|
190
|
+
clan_id=self._clan_id,
|
|
191
|
+
from_name="CLAN_ADMIN"
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
if 'error' not in result:
|
|
195
|
+
print(f"✅ Successfully kicked player with dogtag {dogtag}")
|
|
196
|
+
return True
|
|
197
|
+
else:
|
|
198
|
+
print(f"❌ Failed to kick: {result['error']}")
|
|
199
|
+
return False
|
|
200
|
+
|
|
201
|
+
except Exception as e:
|
|
202
|
+
print(f"❌ Error kicking member: {e}")
|
|
203
|
+
return False
|
|
204
|
+
|
|
205
|
+
def update_clan_settings(self, name: Optional[str] = None,
|
|
206
|
+
description: Optional[str] = None,
|
|
207
|
+
member_limit: Optional[int] = None) -> bool:
|
|
208
|
+
"""
|
|
209
|
+
Update your clan settings.
|
|
210
|
+
|
|
211
|
+
Args:
|
|
212
|
+
name: New clan name (optional)
|
|
213
|
+
description: New clan description (optional)
|
|
214
|
+
member_limit: New member limit (optional)
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
True if successful, False otherwise
|
|
218
|
+
"""
|
|
219
|
+
if not self._clan_id:
|
|
220
|
+
print("❌ No clan detected")
|
|
221
|
+
return False
|
|
222
|
+
|
|
223
|
+
try:
|
|
224
|
+
# Build settings dict with only provided values
|
|
225
|
+
settings = {}
|
|
226
|
+
if name:
|
|
227
|
+
settings['name'] = name
|
|
228
|
+
if description:
|
|
229
|
+
settings['description'] = description
|
|
230
|
+
if member_limit:
|
|
231
|
+
settings['member_limit'] = str(member_limit)
|
|
232
|
+
|
|
233
|
+
if not settings:
|
|
234
|
+
print("⚠️ No settings to update")
|
|
235
|
+
return False
|
|
236
|
+
|
|
237
|
+
result = self.client.update_clan_settings(self._clan_id, **settings)
|
|
238
|
+
|
|
239
|
+
if 'error' not in result:
|
|
240
|
+
print(f"✅ Clan settings updated successfully")
|
|
241
|
+
return True
|
|
242
|
+
else:
|
|
243
|
+
print(f"❌ Failed to update settings: {result['error']}")
|
|
244
|
+
return False
|
|
245
|
+
|
|
246
|
+
except Exception as e:
|
|
247
|
+
print(f"❌ Error updating clan settings: {e}")
|
|
248
|
+
return False
|
|
249
|
+
|
|
250
|
+
def send_message(self, dogtag: str, message: str) -> bool:
|
|
251
|
+
"""
|
|
252
|
+
Send a private message to a player.
|
|
253
|
+
|
|
254
|
+
Args:
|
|
255
|
+
dogtag: Player's dogtag
|
|
256
|
+
message: Message to send
|
|
257
|
+
|
|
258
|
+
Returns:
|
|
259
|
+
True if successful, False otherwise
|
|
260
|
+
"""
|
|
261
|
+
try:
|
|
262
|
+
# First get player info to find their credential
|
|
263
|
+
player_info = self.client.get_player_stats_by_dogtag(dogtag)
|
|
264
|
+
if 'error' in player_info:
|
|
265
|
+
print(f"❌ Player not found: {player_info['error']}")
|
|
266
|
+
return False
|
|
267
|
+
|
|
268
|
+
# Get credential from player data
|
|
269
|
+
player_credential = list(player_info.keys())[0]
|
|
270
|
+
|
|
271
|
+
# Send message
|
|
272
|
+
result = self.client.send_private_message(
|
|
273
|
+
credential=player_credential,
|
|
274
|
+
message=message
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
if 'error' not in result:
|
|
278
|
+
print(f"✅ Message sent to {dogtag}")
|
|
279
|
+
return True
|
|
280
|
+
else:
|
|
281
|
+
print(f"❌ Failed to send message: {result['error']}")
|
|
282
|
+
return False
|
|
283
|
+
|
|
284
|
+
except Exception as e:
|
|
285
|
+
print(f"❌ Error sending message: {e}")
|
|
286
|
+
return False
|
|
287
|
+
|
|
288
|
+
def get_inactive_members(self, days_inactive: int = 30) -> List[Dict[str, Any]]:
|
|
289
|
+
"""
|
|
290
|
+
Get members who haven't been active for specified days.
|
|
291
|
+
|
|
292
|
+
Args:
|
|
293
|
+
days_inactive: Number of days to consider inactive
|
|
294
|
+
|
|
295
|
+
Returns:
|
|
296
|
+
List of inactive members
|
|
297
|
+
"""
|
|
298
|
+
if not self._clan_id:
|
|
299
|
+
print("❌ No clan detected")
|
|
300
|
+
return []
|
|
301
|
+
|
|
302
|
+
try:
|
|
303
|
+
members = self.client.get_clan_members(self._clan_id)
|
|
304
|
+
inactive_members = []
|
|
305
|
+
|
|
306
|
+
for member in members:
|
|
307
|
+
# Check last online time (simplified - you'd need to parse actual date)
|
|
308
|
+
if not member.get('online', False):
|
|
309
|
+
# In a real implementation, you'd check the last_online timestamp
|
|
310
|
+
# For now, we'll consider offline members as potentially inactive
|
|
311
|
+
inactive_members.append({
|
|
312
|
+
'name': member.get('name', 'Unknown'),
|
|
313
|
+
'level': member.get('level', 0),
|
|
314
|
+
'xp': member.get('_xp', 0),
|
|
315
|
+
'status': member.get('status', 'Unknown'),
|
|
316
|
+
'online': False
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
return inactive_members
|
|
320
|
+
|
|
321
|
+
except Exception as e:
|
|
322
|
+
print(f"❌ Error getting inactive members: {e}")
|
|
323
|
+
return []
|
|
324
|
+
|
|
325
|
+
def auto_kick_inactive_members(self, days_inactive: int = 30, dry_run: bool = True) -> Dict[str, Any]:
|
|
326
|
+
"""
|
|
327
|
+
Automatically kick inactive members with safety checks.
|
|
328
|
+
|
|
329
|
+
Args:
|
|
330
|
+
days_inactive: Days of inactivity to trigger kick
|
|
331
|
+
dry_run: If True, only show who would be kicked without actually kicking
|
|
332
|
+
|
|
333
|
+
Returns:
|
|
334
|
+
Dictionary with results
|
|
335
|
+
"""
|
|
336
|
+
inactive_members = self.get_inactive_members(days_inactive)
|
|
337
|
+
|
|
338
|
+
if not inactive_members:
|
|
339
|
+
return {'kicked': 0, 'skipped': 0, 'members': []}
|
|
340
|
+
|
|
341
|
+
results = {'kicked': 0, 'skipped': 0, 'members': []}
|
|
342
|
+
|
|
343
|
+
for member in inactive_members:
|
|
344
|
+
# Safety checks
|
|
345
|
+
if member['level'] > 50: # Don't kick high-level members
|
|
346
|
+
print(f"⚠️ Skipping {member['name']} (Level {member['level']} - too high)")
|
|
347
|
+
results['skipped'] += 1
|
|
348
|
+
continue
|
|
349
|
+
|
|
350
|
+
if 'leader' in member['status'].lower() or 'admin' in member['status'].lower():
|
|
351
|
+
print(f"⚠️ Skipping {member['name']} ({member['status']} - protected role)")
|
|
352
|
+
results['skipped'] += 1
|
|
353
|
+
continue
|
|
354
|
+
|
|
355
|
+
if dry_run:
|
|
356
|
+
print(f"🔍 Would kick: {member['name']} (Level {member['level']}) - Inactive for {days_inactive}+ days")
|
|
357
|
+
else:
|
|
358
|
+
# Note: This would need the member's dogtag, which we'd need to fetch
|
|
359
|
+
print(f"🔨 Kicking {member['name']} (Level {member['level']})")
|
|
360
|
+
# client.kick_member(member['dogtag'], f"Inactive for {days_inactive} days")
|
|
361
|
+
results['kicked'] += 1
|
|
362
|
+
|
|
363
|
+
results['members'].append(member)
|
|
364
|
+
|
|
365
|
+
return results
|
|
366
|
+
|
|
367
|
+
def close(self):
|
|
368
|
+
"""Close the connection."""
|
|
369
|
+
try:
|
|
370
|
+
if self.client:
|
|
371
|
+
self.client.close()
|
|
372
|
+
print("✅ Connection closed")
|
|
373
|
+
except:
|
|
374
|
+
pass
|
|
375
|
+
|
|
376
|
+
def __enter__(self):
|
|
377
|
+
"""Context manager entry."""
|
|
378
|
+
return self
|
|
379
|
+
|
|
380
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
381
|
+
"""Context manager exit."""
|
|
382
|
+
self.close()
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
# Even simpler interface for absolute beginners
|
|
386
|
+
def quick_search(dogtag: str, username: str, password: str) -> Optional[Dict[str, Any]]:
|
|
387
|
+
"""
|
|
388
|
+
Quick search for a player by dogtag.
|
|
389
|
+
|
|
390
|
+
Args:
|
|
391
|
+
dogtag: Player's dogtag to search
|
|
392
|
+
username: Your MC5 username
|
|
393
|
+
password: Your MC5 password
|
|
394
|
+
|
|
395
|
+
Returns:
|
|
396
|
+
Player information or None if not found
|
|
397
|
+
"""
|
|
398
|
+
with SimpleMC5Client(username, password) as client:
|
|
399
|
+
if client.connect():
|
|
400
|
+
return client.search_player(dogtag)
|
|
401
|
+
return None
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
def quick_kick(dogtag: str, username: str, password: str, reason: str = "Kicked") -> bool:
|
|
405
|
+
"""
|
|
406
|
+
Quick kick a member by dogtag.
|
|
407
|
+
|
|
408
|
+
Args:
|
|
409
|
+
dogtag: Member's dogtag to kick
|
|
410
|
+
username: Your MC5 username
|
|
411
|
+
password: Your MC5 password
|
|
412
|
+
reason: Reason for kicking
|
|
413
|
+
|
|
414
|
+
Returns:
|
|
415
|
+
True if successful, False otherwise
|
|
416
|
+
"""
|
|
417
|
+
with SimpleMC5Client(username, password) as client:
|
|
418
|
+
if client.connect():
|
|
419
|
+
return client.kick_member(dogtag, reason)
|
|
420
|
+
return False
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
def batch_search_players(dogtags: List[str], username: str, password: str) -> Dict[str, Any]:
|
|
424
|
+
"""
|
|
425
|
+
Search for multiple players at once.
|
|
426
|
+
|
|
427
|
+
Args:
|
|
428
|
+
dogtags: List of dogtags to search
|
|
429
|
+
username: Your MC5 username
|
|
430
|
+
password: Your MC5 password
|
|
431
|
+
|
|
432
|
+
Returns:
|
|
433
|
+
Dictionary with search results
|
|
434
|
+
"""
|
|
435
|
+
results = {'found': [], 'not_found': [], 'errors': []}
|
|
436
|
+
|
|
437
|
+
with SimpleMC5Client(username, password) as client:
|
|
438
|
+
if client.connect():
|
|
439
|
+
for dogtag in dogtags:
|
|
440
|
+
try:
|
|
441
|
+
player = client.search_player(dogtag)
|
|
442
|
+
if player:
|
|
443
|
+
results['found'].append(player)
|
|
444
|
+
print(f"✅ Found {dogtag}: {player['kills']:,} kills")
|
|
445
|
+
else:
|
|
446
|
+
results['not_found'].append(dogtag)
|
|
447
|
+
print(f"❌ Not found: {dogtag}")
|
|
448
|
+
except Exception as e:
|
|
449
|
+
results['errors'].append({'dogtag': dogtag, 'error': str(e)})
|
|
450
|
+
print(f"⚠️ Error with {dogtag}: {e}")
|
|
451
|
+
|
|
452
|
+
return results
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
def clan_cleanup(username: str, password: str,
|
|
456
|
+
inactive_days: int = 30,
|
|
457
|
+
min_level: int = 10,
|
|
458
|
+
dry_run: bool = True) -> Dict[str, Any]:
|
|
459
|
+
"""
|
|
460
|
+
Comprehensive clan cleanup with conditional logic.
|
|
461
|
+
|
|
462
|
+
Args:
|
|
463
|
+
username: Your MC5 username
|
|
464
|
+
password: Your MC5 password
|
|
465
|
+
inactive_days: Days of inactivity to consider
|
|
466
|
+
min_level: Minimum level to protect from kicking
|
|
467
|
+
dry_run: If True, only show what would be done
|
|
468
|
+
|
|
469
|
+
Returns:
|
|
470
|
+
Dictionary with cleanup results
|
|
471
|
+
"""
|
|
472
|
+
results = {
|
|
473
|
+
'total_members': 0,
|
|
474
|
+
'active_members': 0,
|
|
475
|
+
'inactive_members': 0,
|
|
476
|
+
'would_kick': 0,
|
|
477
|
+
'protected': 0,
|
|
478
|
+
'actions': []
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
with SimpleMC5Client(username, password) as client:
|
|
482
|
+
if not client.connect():
|
|
483
|
+
return results
|
|
484
|
+
|
|
485
|
+
members = client.get_clan_members()
|
|
486
|
+
results['total_members'] = len(members)
|
|
487
|
+
|
|
488
|
+
for member in members:
|
|
489
|
+
# Conditional logic for each member
|
|
490
|
+
if member.get('online', False):
|
|
491
|
+
results['active_members'] += 1
|
|
492
|
+
results['actions'].append(f"✅ {member['name']} - Online (protected)")
|
|
493
|
+
continue
|
|
494
|
+
|
|
495
|
+
# Check level protection
|
|
496
|
+
if member.get('level', 0) >= min_level:
|
|
497
|
+
results['protected'] += 1
|
|
498
|
+
results['actions'].append(f"🛡️ {member['name']} - Level {member['level']} (protected)")
|
|
499
|
+
continue
|
|
500
|
+
|
|
501
|
+
# Check role protection
|
|
502
|
+
status = member.get('status', '').lower()
|
|
503
|
+
if any(role in status for role in ['leader', 'admin', 'officer']):
|
|
504
|
+
results['protected'] += 1
|
|
505
|
+
results['actions'].append(f"👑 {member['name']} - {member['status']} (protected)")
|
|
506
|
+
continue
|
|
507
|
+
|
|
508
|
+
# Member is inactive and not protected
|
|
509
|
+
results['inactive_members'] += 1
|
|
510
|
+
results['would_kick'] += 1
|
|
511
|
+
|
|
512
|
+
if dry_run:
|
|
513
|
+
results['actions'].append(f"🔍 Would kick: {member['name']} - Level {member['level']}, Inactive")
|
|
514
|
+
else:
|
|
515
|
+
# Note: Would need dogtag for actual kicking
|
|
516
|
+
results['actions'].append(f"🔨 Kicked: {member['name']} - Level {member['level']}")
|
|
517
|
+
|
|
518
|
+
return results
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
def monitor_clan_activity(username: str, password: str,
|
|
522
|
+
check_interval: int = 60,
|
|
523
|
+
max_checks: int = 10) -> None:
|
|
524
|
+
"""
|
|
525
|
+
Monitor clan activity with while loop.
|
|
526
|
+
|
|
527
|
+
Args:
|
|
528
|
+
username: Your MC5 username
|
|
529
|
+
password: Your MC5 password
|
|
530
|
+
check_interval: Seconds between checks
|
|
531
|
+
max_checks: Maximum number of checks to perform
|
|
532
|
+
"""
|
|
533
|
+
import time
|
|
534
|
+
|
|
535
|
+
check_count = 0
|
|
536
|
+
|
|
537
|
+
with SimpleMC5Client(username, password) as client:
|
|
538
|
+
if not client.connect():
|
|
539
|
+
return
|
|
540
|
+
|
|
541
|
+
print(f"🔍 Starting clan activity monitoring (checking every {check_interval}s)")
|
|
542
|
+
|
|
543
|
+
while check_count < max_checks:
|
|
544
|
+
check_count += 1
|
|
545
|
+
|
|
546
|
+
try:
|
|
547
|
+
members = client.get_clan_members()
|
|
548
|
+
online_count = sum(1 for m in members if m.get('online', False))
|
|
549
|
+
|
|
550
|
+
print(f"Check {check_count}/{max_checks}: {online_count}/{len(members)} members online")
|
|
551
|
+
|
|
552
|
+
# Conditional alerts
|
|
553
|
+
if online_count == 0:
|
|
554
|
+
print("🚨 Alert: No members online!")
|
|
555
|
+
elif online_count > len(members) * 0.8:
|
|
556
|
+
print("🎉 High activity: Most members are online!")
|
|
557
|
+
|
|
558
|
+
# Break if all members are online
|
|
559
|
+
if online_count == len(members):
|
|
560
|
+
print("✅ All members are online! Stopping monitor.")
|
|
561
|
+
break
|
|
562
|
+
|
|
563
|
+
except Exception as e:
|
|
564
|
+
print(f"⚠️ Error during check {check_count}: {e}")
|
|
565
|
+
|
|
566
|
+
# Wait before next check (except after last check)
|
|
567
|
+
if check_count < max_checks:
|
|
568
|
+
time.sleep(check_interval)
|
|
569
|
+
|
|
570
|
+
print(f"🏁 Monitoring completed after {check_count} checks")
|