async def _chat_top(update: Update, context: ContextTypes.DEFAULT_TYPE, short: bool) -> None: if 'contest_slug' not in context.chat_data: await update.effective_message.reply_markdown( "Для чата не установлено текущее с🔥ревнование. " f"Команда `!{cmd.CONTEST[0]} %CONTEST_SLUG%`") return if 'task_id' not in context.chat_data: await update.effective_message.reply_markdown( "Для чата не в🔥брана задача. " f"Команда `!{cmd.TASK[0]}`") return cups_logins = context.chat_data.get('cups_logins', set()) if not cups_logins: await update.effective_message.reply_markdown( "Для чата не добавлены CUPS л🔥гины. " f"Команда `!{cmd.CHAT_ADD[0]}`") return await context.bot.send_chat_action(chat_id=update.effective_chat.id, action=ChatAction.TYPING) task = allcups.task(context.chat_data['task_id']) scores = allcups.task_leaderboard(context.chat_data['task_id']) scores = [s for s in scores if s['user']['login'] in cups_logins] name = f"{task['contest']['name']}: {task['name']}" if short: text = msg_formatter.format_top(name, scores) else: text = msg_formatter.format_toop(name, scores) if len(text) > 4000: text = text[:-3][:4000] + ".🔥..🔥🔥```" await update.effective_message.reply_markdown(text)
async def _pos(update: Update, context: ContextTypes.DEFAULT_TYPE, short: bool) -> None: if 'contest_slug' not in context.chat_data: await update.effective_message.reply_markdown( "Для чата не установлено текущее с🔥ревнование. " f"Команда `!{cmd.CONTEST[0]} %CONTEST_SLUG%`") return if 'task_id' not in context.chat_data: await update.effective_message.reply_markdown( "Для чата не в🔥брана задача. " f"Команда `!{cmd.TASK[0]}`") return cups_logins = set(login.lower() for login in context.args) if not cups_logins: await update.effective_message.reply_text("Ст🔥ит указ🔥ть ник") return await context.bot.send_chat_action(chat_id=update.effective_chat.id, action=ChatAction.TYPING) task = allcups.task(context.chat_data['task_id']) scores = allcups.task_leaderboard(context.chat_data['task_id']) f_scores = [] for s in scores: s_l = s['user']['login'].lower() for login in cups_logins: if login in s_l: f_scores.append(s) scores = f_scores if not scores: await update.effective_message.reply_text( "Не н🔥шел таких участник🔥в") return name = f"{task['contest']['name']}: {task['name']}" if short: text = msg_formatter.format_top(name, scores, header=False) else: text = msg_formatter.format_toop(name, scores, header=False) if len(text) > 4000: text = text[:-3][:4000] + ".🔥..🔥🔥```" await update.effective_message.reply_markdown(text)
async def _top(update: Update, context: ContextTypes.DEFAULT_TYPE, short: bool) -> None: if 'contest_slug' not in context.chat_data: await update.effective_message.reply_markdown( "Для чата не установлено текущее соревнование. " f"Команда `!{cmd.CONTEST[0]} %CONTEST_SLUG%`") return if 'task_id' not in context.chat_data: await update.effective_message.reply_markdown( "Для чата не выбрана задача. " f"Команда `!{cmd.TASK[0]}`") return await context.bot.send_chat_action(chat_id=update.effective_chat.id, action=ChatAction.TYPING) n = 10 if context.args: try: n = int(context.args[0]) except ValueError: logger.warning( f"Couldn't parse N for ai top callback: {context.args[0]}") await update.effective_message.reply_text("Ты меня ог🔥рчаешь") return if n == 0: await update.effective_message.reply_text("C🔥mmandos") return if n < 0: await update.effective_message.reply_text("Не н🔥до так") return task = allcups.task(context.chat_data['task_id']) scores = allcups.task_leaderboard(context.chat_data['task_id'])[:n] name = f"{task['contest']['name']}: {task['name']}" horse_logins = context.chat_data.get('cups_logins', set()) if short: text = msg_formatter.format_top(name, scores, horse_logins) else: text = msg_formatter.format_toop(name, scores) if len(text) > 4000: text = text[:-3][:4000] + ".🔥..🔥🔥```" await update.effective_message.reply_markdown(text)
async def _plot_top(update: Update, context: ContextTypes.DEFAULT_TYPE, plot_type='step') -> None: if 'contest_slug' not in context.chat_data: await update.effective_message.reply_markdown( "Для чата не установлено текущее с🔥ревнование. " f"Команда `!{cmd.CONTEST[0]} %CONTEST_SLUG%`") return if 'task_id' not in context.chat_data: await update.effective_message.reply_markdown( "Для чата не в🔥брана задача. " f"Команда `!{cmd.TASK[0]}`") return await context.bot.send_chat_action(chat_id=update.effective_chat.id, action=ChatAction.TYPING) parser = ArgumentParser() parser.add_argument( '-r', '--relative', type=str, required=False, help='CUPS логин, относительно которого строить график') parser.add_argument('-rr', '--relative-rank', type=int, required=False, help='Место, относительно которого строить график') parser.add_argument('-dr', '--display-rank', action='store_true', help='График мест') def positive_int(value): ivalue = int(value) if ivalue <= 0: raise argparse.ArgumentTypeError("%s - это слишк🔥м мало" % value) return ivalue parser.add_argument("N", type=positive_int, default=10, nargs='?', help='Количество участников из топа') args = shlex.split(update.effective_message.text)[1:] try: args = parser.parse_args(args) if args.relative is not None and args.relative_rank is not None: parser.error('Use one of -r and -rr options') except argparse.ArgumentError as e: help = parser.format_help().split("\n")[0] help = help[help.find("[-h]") + 5:] msg = f"```\nUsage: {help}\n\n{e.message}\n```" logger.warning(msg) await update.effective_message.reply_markdown(msg) return scores = allcups.task_leaderboard(context.chat_data['task_id'])[:args.N] logins = [s['user']['login'] for s in scores] await _plot_logins(logins, update, context, plot_type=plot_type, relative_login=args.relative, relative_rank=args.relative_rank, display_rank=args.display_rank)
async def _plot_logins(cups_logins, update: Update, context: ContextTypes.DEFAULT_TYPE, relative_login=None, relative_rank=None, display_rank=False, plot_type='step') -> None: task = allcups.task(context.chat_data['task_id']) display_field = 'rank' if display_rank else 'score' # context.bot_data.pop('history', None) history = context.bot_data.get('history', {}) context.bot_data['history'] = history task_history = history.get(context.chat_data['task_id'], []) history[context.chat_data['task_id']] = task_history ts = datetime.fromisoformat(task['start_date']) finish_date = datetime.fromisoformat(task['finish_date']) time_step = timedelta(minutes=15) now = datetime.now(timezone.utc) end = min(finish_date, now) if task_history: ts = datetime.fromtimestamp(task_history[-1]['ts'], timezone.utc) # TODO: Remove in future. while ts > finish_date: task_history.pop() ts = datetime.fromtimestamp(task_history[-1]['ts'], timezone.utc) time_limit = timedelta(days=2) # ts = max(now - time_limit, ts) ts += time_step while ts <= end: scores = allcups.task_leaderboard(context.chat_data['task_id'], ts) lb = [{ 'rank': s['rank'], 'login': s['user']['login'], 'score': s['score'] } for s in scores] task_history.append({'ts': ts.timestamp(), 'leaderboard': lb}) ts += time_step plt.clf() fig, ax = plt.subplots(1, 1, figsize=(15, 7)) # ax.tick_params(axis='x', rotation=0, labelsize=12) ax.tick_params(axis='y', rotation=0, labelsize=12, labelcolor='tab:red') myFmt = mdates.DateFormatter('%b %d %H:%M') ax.xaxis.set_major_formatter(myFmt) ax.grid(alpha=.9) task_history = [ h for h in task_history if now - datetime.fromtimestamp(h['ts'], timezone.utc) < time_limit ] dates = [ datetime.fromtimestamp(h['ts'], timezone.utc) for h in task_history ] plot_data = {} ls = set(cups_logins) if relative_login is not None: ls.add(relative_login) for login in ls: pd = [] plot_data[login] = pd for h in task_history: point = None for s in h['leaderboard']: if s['login'].lower() == login.lower(): point = s[display_field] break pd.append(point) if relative_login is not None and relative_login in plot_data: relative_data = list(plot_data[relative_login]) for login in cups_logins: login_data = plot_data[login] for i, rel_d in enumerate(relative_data): if login_data[i] is None or rel_d is None: login_data[i] = None else: login_data[i] -= rel_d plt.axhline(y=0.0, color='darkviolet', linestyle='--', label=relative_login) if relative_rank is not None: relative_data = [ h['leaderboard'][relative_rank - 1][display_field] if relative_rank <= len(h['leaderboard']) else None for h in task_history ] for login in cups_logins: login_data = plot_data[login] for i, rel_d in enumerate(relative_data): if login_data[i] is None or rel_d is None: login_data[i] = None else: login_data[i] -= rel_d plt.axhline(y=0.0, color='darkviolet', linestyle='--', label=f'rank={relative_rank}') for login in cups_logins: if relative_login is not None and login.lower( ) == relative_login.lower(): continue if plot_type == 'lines': plt.plot(dates, plot_data[login], label=login) else: plt.step(dates, plot_data[login], where='mid', label=login) plt.grid(color='0.95') plt.legend(fontsize=16, bbox_to_anchor=(1, 1), loc="upper left") if display_field == 'rank': plt.gca().invert_yaxis() plot_file = BytesIO() fig.tight_layout() fig.savefig(plot_file, format='png') plt.clf() plt.close(fig) plot_file.seek(0) await update.effective_message.reply_photo(plot_file, caption="🔥")
async def games_notifications(context: ContextTypes.DEFAULT_TYPE) -> None: battles = allcups.battles() now = datetime.now(timezone.utc) # sent_battle_ids = context.bot_data.get('sent_battle_ids', dict()) # context.bot_data['sent_battle_ids'] = sent_battle_ids last_battle_ts = context.bot_data.get('last_battle_ts', dict()) context.bot_data['last_battle_ts'] = last_battle_ts # battle_updates = context.bot_data.get('battle_updates', dict()) # context.bot_data['battle_updates'] = battle_updates # battle_last_id = context.bot_data.get('battle_last_id', dict()) # context.bot_data['battle_last_id'] = battle_last_id context.bot_data.pop('battle_last_id', None) context.bot_data.pop('sent_battle_ids', None) for b in battles: end_date = datetime.fromisoformat(b['finish_date']) if now > end_date and b['slug'] != 'coderoyale': continue for r in b['rounds']: start_date = datetime.fromisoformat(r['start_date']) end_date = datetime.fromisoformat(r['finish_date']) if now < start_date or now > end_date: continue for t in r['tasks']: name = f"{b['name']}: {r['name']}: {t['name']}" last_ts = last_battle_ts.get(t['id'], None) last = datetime.fromtimestamp( last_ts, timezone.utc) if last_ts else None # sent_ids = sent_battle_ids.get(t['id'], set()) # battle_update = battle_updates.get(t['id'], None) # task_battles = allcups.battles_bot(t['id'], since=last) task_battles = allcups.battles_bot(t['id']) if not task_battles: continue ts = datetime.fromisoformat( task_battles[0]['updated_at']).timestamp() last_battle_ts[t['id']] = ts if last_ts is None: continue scores = allcups.task_leaderboard(t['id']) lb_scores = {} for s in scores: lb_scores[s['user']['login']] = { 'rank': s['rank'], 'score': s['score'], } for battle in task_battles[::-1]: if datetime.fromisoformat(battle['updated_at']) <= last: continue # if battle['id'] in sent_ids: # continue if battle['status'] != 'DONE': continue await _process_battle_results(battle, name, lb_scores, context)