· 6 months ago · Apr 08, 2025, 10:25 AM
1import os
2import json
3import requests
4from collections import defaultdict
5from typing import Dict, Optional, List, Tuple
6
7MOJANG_API = "https://api.mojang.com/user/profile/"
8
9def get_username(uuid: str) -> Optional[str]:
10 """Get the username from a UUID using the Mojang API."""
11 response = requests.get(f"{MOJANG_API}{uuid}")
12
13 if response.status_code == 200:
14 data = response.json()
15 return data.get('name')
16 return None
17
18def validate_path(path: str) -> bool:
19 """Validate the provided path."""
20 if not os.path.exists(path):
21 print("Invalid path. Please try again.")
22 return False
23
24 if not os.path.isdir(path):
25 print("The path is not a directory. Please try again.")
26 return False
27
28 if not os.listdir(path):
29 print("The directory is empty. Please try again.")
30 return False
31
32 if not any(os.path.isfile(os.path.join(path, f)) for f in os.listdir(path)):
33 print("The directory does not contain any files. Please try again.")
34 return False
35
36 return True
37
38def process_advancements(path: str, whitelist: List[str]) -> Tuple[Dict[str, int], Dict[str, int]]:
39 """Process advancement files and return advancements and user counts."""
40 advancements = defaultdict(int)
41 users = {}
42
43 for userfile in os.listdir(path):
44 if not userfile.endswith(".json"):
45 print(f"{userfile} is not a valid JSON file")
46 continue
47
48 uuid = userfile.split(".")[0]
49 user_count = 0
50
51 try:
52 with open(os.path.join(path, userfile), 'r') as f:
53 data = json.load(f)
54
55 for key, value in data.items():
56 if not isinstance(value, dict) or not value.get("done", False):
57 continue
58
59 # Check if advancement matches whitelist criteria
60 matches_whitelist = not whitelist or any(key.startswith(item) for item in whitelist)
61
62 if matches_whitelist:
63 advancements[key] += 1
64 user_count += 1
65 except json.JSONDecodeError:
66 print(f"Error decoding JSON in file {userfile}")
67 continue
68 except Exception as e:
69 print(f"Error processing file {userfile}: {e}")
70 continue
71
72 users[uuid] = user_count
73
74 return dict(advancements), users
75
76def display_results(advancements: Dict[str, int], users: Dict[str, int]) -> None:
77 """Display the results in a readable format."""
78 # Sort users by advancement count
79 sorted_users = sorted(users.items(), key=lambda item: item[1], reverse=True)
80
81 # Print top 10 users
82 print("\nTop 10 users:")
83 for i, (uuid, count) in enumerate(sorted_users[:10]):
84 username = get_username(uuid)
85 print(f"{username or 'Unknown'} ({uuid}): {count}")
86
87 # Print statistics
88 print(f"\nTotal number of users: {len(users)}")
89 print(f"Total number of advancements found: {len(advancements)}")
90
91 # Sort advancements by count
92 sorted_advancements = sorted(advancements.items(), key=lambda item: item[1], reverse=True)
93
94 # Print advancements
95 print("\nAdvancements:")
96 for advancement, count in sorted_advancements:
97 print(f"{advancement}: {count}")
98
99def main():
100 path = input("Enter the path to the Advancements folder: ")
101 whitelist_input = input("Enter advancements whitelist (ex. minecraft:mines,minecraft:unlocks): ")
102 whitelist = [item.strip() for item in whitelist_input.split(",")] if whitelist_input else []
103
104 if not validate_path(path):
105 return
106
107 advancements, users = process_advancements(path, whitelist)
108 display_results(advancements, users)
109
110if __name__ == "__main__":
111 main()