feat: rescan_existing_tournaments — detect new players in cached tournaments every 2h
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 6s

This commit is contained in:
vrubel 2026-06-20 22:09:48 +00:00
parent 07b016bff9
commit d18c5016ce
2 changed files with 75 additions and 0 deletions

View file

@ -371,6 +371,16 @@ def _fetch_and_parse_art0(tnr: int) -> dict | None:
return parsed
def _refetch_art0(tnr: int) -> dict | None:
"""Always fetch art=0 via HTTP, update cache. Returns parsed dict or None."""
html = _fetch_art0(tnr)
if html is None:
return None
parsed = _parse_art0_page(html)
_save_tnr_cache(tnr, parsed)
return parsed
# ═══ Tournament scanner (art=0 pages) ═══
ART0_URL = 'https://chess-results.com/tnr{tnr}.aspx?lan=11&art=0&turdet=YES'
@ -684,6 +694,69 @@ def _warmup_cache_sync():
set_tnr_state('warmup_tnr', 'done')
async def rescan_existing_tournaments(context):
"""Every 2h: refetch art=0 for all cached TNRs, detect new players."""
import time
from bots.client_bot import _md_escape as _md_esc
conn = _get_conn()
cached_tnrs = [r[0] for r in conn.execute('SELECT tnr FROM tnr_cache ORDER BY tnr DESC').fetchall()]
conn.close()
if not cached_tnrs:
return
# Collect subscribed FIDE IDs and their users
conn = _get_conn()
sub_rows = conn.execute(
'SELECT DISTINCT user_id, fide_id, lang FROM subscriptions WHERE active = 1'
).fetchall()
conn.close()
if not sub_rows:
return
fide_to_users = {}
for user_id, fide_id, lang in sub_rows:
fide_to_users.setdefault(fide_id, []).append((user_id, lang))
for tnr in cached_tnrs:
old_data = _get_cached_tnr(tnr)
old_fids = set(old_data['players'].keys()) if old_data else set()
new_data = _refetch_art0(tnr)
if new_data is None:
continue # tournament deleted or unreachable
new_fids = set(new_data['players'].keys())
# New players that appeared since last cached snapshot
appeared = new_fids - old_fids
for fid in appeared:
if fid not in fide_to_users:
continue
player_info = new_data['players'][fid]
url = f'https://chess-results.com/tnr{tnr}.aspx?lan=11'
for user_id, lang in fide_to_users[fid]:
player = {'fide_id': fid, 'name': player_info['name'],
'rating': player_info.get('rating', 0), 'fed': ''}
add_subscription(
user_id, player, url, new_data['name'] or f'Tournament {tnr}',
player_info['sno'], 0, 0.0, lang,
new_data.get('start_date', ''), new_data.get('end_date', ''))
try:
safe_name = _md_esc(player_info['name'])
safe_tour = _md_esc(new_data['name'] or f'Tournament {tnr}')
dates = ''
if new_data.get('start_date') and new_data.get('end_date'):
dates = f'\\({new_data["start_date"]}{new_data["end_date"]}\\)'
await context.bot.send_message(
user_id,
f'🆕 *{safe_name}* появился в турнире\!\n'
f'📅 *{safe_tour}*{dates}\n'
'Автоматически подписал — буду отслеживать\.',
parse_mode='MarkdownV2')
except Exception:
pass
time.sleep(0.1)
async def check_all_subscriptions(context):
from swiss_calc.parser import fetch_tournament
from swiss_calc.swiss import calculate_next_round