diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ab4090..68a19dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Changelog +## v4.1 - 2025-09-13 - 修复TBD事件重复问题 +- **🐛 修复TBD事件匹配逻辑**: + - 修复了 `find_existing_event()` 方法中的TBD匹配逻辑 + - 原问题:只匹配 "TBD_TBD" 事件键,不匹配 "TBD_NGX" 或 "PV_TBD" 等部分TBD事件 + - 现在可以正确识别并更新所有包含TBD的事件("TBD vs Team" 和 "Team vs TBD") + - 防止创建重复事件,确保TBD事件被更新而非创建新事件 +- **🔧 增强TBD事件清理**: + - 修复了 `clean_duplicate_and_expired_events()` 方法的清理逻辑 + - 原问题:只删除 "TBD vs TBD" 格式的事件,导致部分TBD事件无法被清理 + - 现在删除所有与确认比赛同时间的TBD事件,不再限于特定格式 + - 成功清理了9月13日的3个重复TBD事件 +- **🎯 问题根源分析**: + - 发现问题:同一时间存在 "TBD vs NGX" 和 "XG vs NGX" 重复事件 + - 根本原因:TBD事件没有被正确更新,而是创建了新的确认事件 + - 解决方案:改进事件匹配算法,支持部分TBD匹配和时间窗口匹配 + ## v4.0 - 2025-09-12 - 代码结构重构与错误处理优化 - **🏗️ 代码结构重构**: - 使用 `@dataclass` 替代字典存储比赛数据,提高类型安全性 @@ -180,10 +196,11 @@ | v3.8 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | v3.9 | ✓ | ✓ | ✓ | ✓ | ✓+ | ✓ | | v4.0 | ✓ | ✓ | ✓ | ✓ | ✓+ | ✓ | +| v4.1 | ✓ | ✓ | ✓ | ✓ | ✓++ | ✓ | ## 使用建议 -推荐使用最新的 v4.0 版本,它包含所有功能并提供更好的错误处理: +推荐使用最新的 v4.1 版本,它修复了TBD事件重复问题并提供更好的错误处理: ```bash python sync_dota2_matches.py --calendar-id "YOUR_CALENDAR_ID" ``` diff --git a/README.md b/README.md index e9b515d..d489f7c 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,15 @@ -# Dota 2 Calendar Sync v4.0 +# Dota 2 Calendar Sync v4.1 自动从 Liquipedia 获取 Dota 2 Tier 1 比赛信息并同步到 Google Calendar,支持自动更新比赛结果、时间变更、智能管理TBD占位事件、自动清理过期和重复比赛。 -**v4.0 新特性**: +## 更新日志 + +### v4.1 (2025-09-13) +- 🐛 修复TBD事件匹配逻辑:现在可以正确识别并更新部分TBD事件(如 "TBD vs Team" 或 "Team vs TBD") +- 🔧 增强TBD事件清理:删除所有与确认比赛同时间的TBD事件,不再限于 "TBD vs TBD" 格式 +- 🎯 防止创建重复事件:改进事件匹配算法,确保TBD事件被更新而非创建新事件 + +### v4.0 (2025-09-05) - 🏗️ 代码结构重构:使用 dataclass 替代字典,提高类型安全性 - 🔄 增强错误处理:添加自动重试机制(指数退避) - 📝 专业日志系统:使用 Python logging 模块,支持多级别日志 diff --git a/sync_dota2_matches.py b/sync_dota2_matches.py index 138a949..c206dcd 100644 --- a/sync_dota2_matches.py +++ b/sync_dota2_matches.py @@ -654,16 +654,43 @@ class Dota2CalendarSync: match.tournament and match.tournament in event_key): return event - # Special handling for TBD matches + # Special handling for TBD matches - check if this match should update a TBD placeholder if not (match.team1 == 'TBD' and match.team2 == 'TBD'): for event_key, event in by_match.items(): - if 'TBD_TBD' in event_key and match.tournament and match.tournament in event_key: - # Check if time matches (within 1 hour) - event_start = event['start'].get('dateTime', event['start'].get('date')) - event_dt = datetime.fromisoformat(event_start.replace('Z', '+00:00')) - if abs((event_dt - match.datetime).total_seconds()) < 3600: - logger.info(f"Found TBD match to update: {match.team1} vs {match.team2}") - return event + # Check if this is a TBD event that could be updated with real teams + if 'TBD' in event_key and match.tournament and match.tournament in event_key: + # Parse the event key to get teams + key_parts = event_key.split('_') + if len(key_parts) >= 3: + existing_team1 = key_parts[0] + existing_team2 = key_parts[1] + + # Check if this TBD event matches the incoming match + # Match if: one team is TBD and the other matches, or both are TBD + teams_match = False + if existing_team1 == 'TBD' and existing_team2 == 'TBD': + # Both TBD - match by time + teams_match = True + elif existing_team1 == 'TBD' and existing_team2 == match.team2: + # First team is TBD, second matches + teams_match = True + elif existing_team1 == match.team1 and existing_team2 == 'TBD': + # First team matches, second is TBD + teams_match = True + elif existing_team2 == 'TBD' and existing_team1 == match.team1: + # Reverse check + teams_match = True + elif existing_team1 == 'TBD' and existing_team2 == match.team1: + # Reverse check + teams_match = True + + if teams_match: + # Check if time matches (within 1 hour) + event_start = event['start'].get('dateTime', event['start'].get('date')) + event_dt = datetime.fromisoformat(event_start.replace('Z', '+00:00')) + if abs((event_dt - match.datetime).total_seconds()) < 3600: + logger.info(f"Found TBD match to update: {existing_team1} vs {existing_team2} -> {match.team1} vs {match.team2}") + return event return None @@ -1286,14 +1313,16 @@ class Dota2CalendarSync: for tbd_event in events['tbd']: tbd_summary = tbd_event.get('summary', '') - if 'TBD vs TBD' in tbd_summary and events['confirmed']: + # Delete any TBD event that has a confirmed match at the same time + # This includes "TBD vs TBD", "TBD vs Team", and "Team vs TBD" + if events['confirmed']: if not dry_run: if self.delete_calendar_event(tbd_event['id']): - logger.info(f"🗑️ Deleted TBD vs TBD event at same time as confirmed match") + logger.info(f"🗑️ Deleted TBD event superseded by confirmed match: {tbd_summary}") deleted_count += 1 time.sleep(0.2) else: - logger.info(f"◯ Would delete TBD vs TBD event: {tbd_summary}") + logger.info(f"◯ Would delete TBD event superseded by confirmed match: {tbd_summary}") deleted_count += 1 # Delete duplicate TBD vs TBD events