| |
| """ |
| dedup_fix_v1560.py — Dedup fix for vnews-zalo-bot-v2 Space |
| Patch app.py khi Space khoi dong. |
| Fix: duplicate notifications + missing events for finished matches |
| """ |
| import re |
|
|
| def patch(): |
| with open('app.py', 'r', encoding='utf-8') as f: |
| content = f.read() |
| |
| original = content |
| changes = [] |
| |
| |
| marker = 'def _notify_match_event(evt):' |
| if marker in content: |
| start = content.find(marker) |
| rest = content[start + len(marker):] |
| lines = rest.split('\n') |
| end_off = 0 |
| for i, line in enumerate(lines): |
| if i == 0: |
| end_off += len(line) + 1 |
| continue |
| if line and not line[0].isspace() and (line.startswith('def ') or line.startswith('class ')): |
| break |
| end_off += len(line) + 1 |
| new_func = marker + '\n """FIX v15.60: DISABLED"""\n return\n' |
| content = content[:start] + new_func + content[start + len(marker) + end_off:] |
| changes.append("FIX 1: Disabled _notify_match_event") |
| |
| |
| marker2 = 'def notify_events(events):' |
| if marker2 in content: |
| start2 = content.find(marker2) |
| rest2 = content[start2 + len(marker2):] |
| lines2 = rest2.split('\n') |
| end_off2 = 0 |
| for i, line in enumerate(lines2): |
| if i == 0: |
| end_off2 += len(line) + 1 |
| continue |
| if line and not line[0].isspace() and (line.startswith('def ') or line.startswith('class ')): |
| break |
| end_off2 += len(line) + 1 |
| new_func2 = marker2 + '\n """FIX v15.60: DISABLED"""\n return\n' |
| content = content[:start2] + new_func2 + content[start2 + len(marker2) + end_off2:] |
| changes.append("FIX 2: Disabled notify_events") |
| |
| |
| old3 = 'if kickoff_passed_min is not None and kickoff_passed_min > 180:' |
| if old3 in content: |
| content = content.replace(old3, 'if False: # FIX v15.60') |
| changes.append("FIX 3: Bo kickoff_passed_min > 180") |
| |
| |
| idx4 = content.find('# 4. Live match events') |
| if idx4 != -1: |
| sub_idx = content.find('if is_live and not is_finished:', idx4) |
| if sub_idx != -1 and sub_idx - idx4 < 200: |
| old_cond = 'if is_live and not is_finished:' |
| new_cond = 'if (is_live and not is_finished) or is_finished: # FIX v15.60' |
| content = content[:sub_idx] + new_cond + content[sub_idx + len(old_cond):] |
| changes.append("FIX 4: Fetch events cho finished") |
| |
| old5 = 'def _check_auto_notifications():\n """Check all matches and send auto notifications to the group."""\n try:' |
| new5 = 'def _check_auto_notifications():\n """Check all matches and send auto notifications to the group."""\n if not hasattr(_check_auto_notifications, "_ft_cooldown"):\n _check_auto_notifications._ft_cooldown = {}\n try:' |
| if old5 in content: |
| content = content.replace(old5, new5, 1) |
| changes.append("FIX 5: Cooldown init") |
| |
| idx6 = content.find('# 3. Match ended') |
| if idx6 != -1: |
| old6 = '_auto_notify_match(eid, "fulltime", m)' |
| sub_idx6 = content.find(old6, idx6) |
| if sub_idx6 != -1: |
| indent = ' ' |
| new6 = ( |
| indent + '_ft_hash = f"fulltime|{eid}"\n' |
| + indent + '_ft_sent = False\n' |
| + indent + 'try:\n' |
| + indent + ' _ft_sent = bool(db_q("SELECT 1 FROM notified_events WHERE user_id=? AND event_id=? AND event_hash=?", (ALLOWED_GROUP_ID, eid, _ft_hash)))\n' |
| + indent + 'except Exception:\n' |
| + indent + ' pass\n' |
| + indent + 'if not _ft_sent:\n' |
| + indent + ' _auto_notify_match(eid, "fulltime", m)\n' |
| ) |
| content = content[:sub_idx6] + new6 + content[sub_idx6 + len(old6):] |
| changes.append("FIX 6: Check notified_events") |
| |
| old7 = 'msg += f"\\n\\n📺 Xem trực tiếp: {VNEWS_SPACE_URL}"\n msg += "\\n💬 Nhắn VNxxx/WCxx để theo dõi tiếp!"' |
| if old7 in content: |
| new7 = ( |
| ' try:\n' |
| ' _ft_ev_lines = _format_events_lines(events, home_vi, away_vi, is_wc=True)\n' |
| ' if _ft_ev_lines:\n' |
| ' msg += "\\n\\n📋 DIỄN BIẾN:"\n' |
| ' msg += "\\n" + "\\n".join(_ft_ev_lines)\n' |
| ' except Exception:\n' |
| ' pass\n' |
| ' msg += f"\\n\\n📺 Xem trực tiếp: {VNEWS_SPACE_URL}"\n' |
| ' msg += "\\n💬 Nhắn VNxxx/WCxx để theo dõi tiếp!"' |
| ) |
| content = content.replace(old7, new7, 1) |
| changes.append("FIX 7: Events summary") |
| |
| old8 = ' if ev_type == "goal":\n _auto_notify_match(eid, "goal", {**m, "scorer": ev.get("scorer", ""), "assist": ev.get("assist", ""), "minute": ev_time})' |
| if old8 in content: |
| new8 = ( |
| ' _ALLOWED_EV_TYPES = {"goal", "redcard", "substitution", "var", "penalty", "penalty_missed", "halftime", "fulltime", "match_start", "second_half_start"}\n' |
| ' if ev_type not in _ALLOWED_EV_TYPES:\n' |
| ' continue\n' |
| ' if ev_type == "goal":\n' |
| ' _auto_notify_match(eid, "goal", {**m, "scorer": ev.get("scorer", ""), "assist": ev.get("assist", ""), "minute": ev_time})' |
| ) |
| content = content.replace(old8, new8, 1) |
| changes.append("FIX 8: Filter events") |
| |
| if content != original: |
| with open('app.py', 'w', encoding='utf-8') as f: |
| f.write(content) |
| for c in changes: |
| print(f"OK {c}") |
| print(f"Done! {len(content)} bytes") |
| else: |
| print("No changes!") |
|
|
| if __name__ == "__main__": |
| patch() |
|
|