HASH 938573c1323d
DATE 2025-08-11
SUBJECT challenge-mode: fix eu merge logic
FILES 2 CHANGED
HASH 938573c1323d
DATE 2025-08-11
SUBJECT challenge-mode: fix eu merge logic
FILES 2 CHANGED
┌─ nix/apps/challenge-mode-leaderboard.nix ──────────────────────────────────┐│ diff --git a/nix/apps/challenge-mode-leaderboard.nix b/nix/apps/challenge-mode-lea ││ derboard.nix ││ index a1da435..05844fd 100644 ││ --- a/nix/apps/challenge-mode-leaderboard.nix ││ +++ b/nix/apps/challenge-mode-leaderboard.nix ││ @@ -102,7 +102,7 @@ ││ ││ ││ def merge_leaderboard_data(existing_path, new_data): ││ - """Merge new leaderboard data with existing data, preserving historical ││ entries.""" ││ + #FIX ME: merge new leaderboard data with existing data, preserving histor ││ ical entries (https://github.com/ClassicWoWCommunity/mop-classic-bugs/issues/2208) ││ if not os.path.exists(existing_path): ││ return new_data ││ ││ @@ -110,18 +110,39 @@ ││ with open(existing_path, 'r', encoding='utf-8') as f: ││ existing_data = json.load(f) ││ ││ - # Get existing and new leading groups ││ + # get existing and new leading groups ││ existing_groups = existing_data.get('leading_groups', []) ││ new_groups = new_data.get('leading_groups', []) ││ ││ - # Merge the leading groups (append new to existing) ││ - merged_groups = existing_groups + new_groups ││ + # combine all groups for deduplication ││ + all_groups = existing_groups + new_groups ││ ││ - # Use new data as base (has current metadata) but with merged group ││ s ││ + # deduplicate runs using the same logic as the parser ││ + seen = set() ││ + deduplicated_groups = [] ││ + ││ + for run in all_groups: ││ + # create a unique identifier for each run using timestamp, dura ││ tion, and sorted player IDs ││ + player_ids = sorted([member["profile"]["id"] for member in run[ ││ "members"]]) ││ + unique_key = (run["completed_timestamp"], run["duration"], tupl ││ e(player_ids)) ││ + ││ + if unique_key not in seen: ││ + seen.add(unique_key) ││ + deduplicated_groups.append(run) ││ + ││ + # sort by duration and re-rank (same logic as parser) ││ + sort_key = lambda run: run["duration"] ││ + deduplicated_groups.sort(key=sort_key) ││ + ││ + # re-rank runs from 1 to N based on sorted order ││ + for i, run in enumerate(deduplicated_groups): ││ + run["ranking"] = i + 1 ││ + ││ + # use new data as base (has current metadata) but with properly sor ││ ted and ranked groups ││ merged_data = new_data.copy() ││ - merged_data['leading_groups'] = merged_groups ││ + merged_data['leading_groups'] = deduplicated_groups ││ ││ - print(f" Merged {len(existing_groups)} existing + {len(new_group ││ s)} new = {len(merged_groups)} total entries") ││ + print(f" Merged {len(existing_groups)} existing + {len(new_group ││ s)} new = {len(deduplicated_groups)} sorted and ranked entries") ││ ││ return merged_data ││ ││ @@ -172,7 +193,7 @@ ││ ) ││ os.makedirs(os.path.dirname(output_path), exist_ok=True) ││ ││ - # For EU realms, merge with existing data to preserve historica ││ l records ││ + # for EU realms, merge with existing data to preserve historica ││ l records ││ if realm_info['region'] == 'eu': ││ final_data = merge_leaderboard_data(output_path, leaderboar ││ d) ││ else: │└────────────────────────────────────────────────────────────────────────────────────┘
┌─ ...hallenge-mode-leaderboard.nix ───┐│ diff --git a/nix/apps/challenge-mode-leaderb ││ oard.nix b/nix/apps/challenge-mode-leaderboa ││ rd.nix ││ index a1da435..05844fd 100644 ││ --- a/nix/apps/challenge-mode-leaderboard.ni ││ x ││ +++ b/nix/apps/challenge-mode-leaderboard.ni ││ x ││ @@ -102,7 +102,7 @@ ││ ││ ││ def merge_leaderboard_data(existing_p ││ ath, new_data): ││ - """Merge new leaderboard data wit ││ h existing data, preserving historical entri ││ es.""" ││ + #FIX ME: merge new leaderboard data ││ with existing data, preserving historical e ││ ntries (https://github.com/ClassicWoWCommuni ││ ty/mop-classic-bugs/issues/2208) ││ if not os.path.exists(existing_pa ││ th): ││ return new_data ││ ││ @@ -110,18 +110,39 @@ ││ with open(existing_path, 'r', ││ encoding='utf-8') as f: ││ existing_data = json.load ││ (f) ││ ││ - # Get existing and new leadin ││ g groups ││ + # get existing and new leadin ││ g groups ││ existing_groups = existing_da ││ ta.get('leading_groups', []) ││ new_groups = new_data.get('le ││ ading_groups', []) ││ ││ - # Merge the leading groups (a ││ ppend new to existing) ││ - merged_groups = existing_grou ││ ps + new_groups ││ + # combine all groups for dedu ││ plication ││ + all_groups = existing_groups ││ + new_groups ││ ││ - # Use new data as base (has c ││ urrent metadata) but with merged groups ││ + # deduplicate runs using the ││ same logic as the parser ││ + seen = set() ││ + deduplicated_groups = [] ││ + ││ + for run in all_groups: ││ + # create a unique identif ││ ier for each run using timestamp, duration, ││ and sorted player IDs ││ + player_ids = sorted([memb ││ er["profile"]["id"] for member in run["membe ││ rs"]]) ││ + unique_key = (run["comple ││ ted_timestamp"], run["duration"], tuple(play ││ er_ids)) ││ + ││ + if unique_key not in seen ││ : ││ + seen.add(unique_key) ││ + deduplicated_groups.a ││ ppend(run) ││ + ││ + # sort by duration and re-ran ││ k (same logic as parser) ││ + sort_key = lambda run: run["d ││ uration"] ││ + deduplicated_groups.sort(key= ││ sort_key) ││ + ││ + # re-rank runs from 1 to N ba ││ sed on sorted order ││ + for i, run in enumerate(dedup ││ licated_groups): ││ + run["ranking"] = i + 1 ││ + ││ + # use new data as base (has c ││ urrent metadata) but with properly sorted an ││ d ranked groups ││ merged_data = new_data.copy() ││ - merged_data['leading_groups'] ││ = merged_groups ││ + merged_data['leading_groups'] ││ = deduplicated_groups ││ ││ - print(f" Merged {len(exist ││ ing_groups)} existing + {len(new_groups)} ne ││ w = {len(merged_groups)} total entries") ││ + print(f" Merged {len(exist ││ ing_groups)} existing + {len(new_groups)} ne ││ w = {len(deduplicated_groups)} sorted and ra ││ nked entries") ││ ││ return merged_data ││ ││ @@ -172,7 +193,7 @@ ││ ) ││ os.makedirs(os.path.dirna ││ me(output_path), exist_ok=True) ││ ││ - # For EU realms, merge wi ││ th existing data to preserve historical reco ││ rds ││ + # for EU realms, merge wi ││ th existing data to preserve historical reco ││ rds ││ if realm_info['region'] = ││ = 'eu': ││ final_data = merge_le ││ aderboard_data(output_path, leaderboard) ││ else: │└──────────────────────────────────────────────┘