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 _games(update: Update, context: ContextTypes.DEFAULT_TYPE) -> 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 if not context.args: await update.effective_message.reply_text("Ст🔥ит указ🔥ть ник") return cups_login = context.args[0] await context.bot.send_chat_action(chat_id=update.effective_chat.id, action=ChatAction.TYPING) task = allcups.task(context.chat_data['task_id']) battles = allcups.battles(context.chat_data['task_id'], max_count=10, search=cups_login.lower())[:10] if not battles: await update.effective_message.reply_text( "Не н🔥шел таких участник🔥в") return name = f"{task['contest']['name']}: {task['name']}" text = msg_formatter.format_battles(name, cups_login, battles) await update.effective_message.reply_markdown(text)
async def _info(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: contest = None task = None if 'contest_slug' in context.chat_data: contest = allcups.contest(context.chat_data['contest_slug']) if 'task_id' in context.chat_data: task = allcups.task(context.chat_data['task_id']) info_txt = msg_formatter.format_chat_info(contest, task) battle_login = context.chat_data.get('battle_login', None) if battle_login: info_txt += f"\nCUPS Battle Login: `{battle_login}`" await update.effective_message.reply_markdown(info_txt)
async def _task_button(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: """Parses the CallbackQuery and updates the message text.""" query = update.callback_query # CallbackQueries need to be answered, even if no notification to the user is needed # Some clients may have trouble otherwise. See https://core.telegram.org/bots/api#callbackquery await query.answer() task_id = query.data.split()[1] task = allcups.task(task_id) contest = allcups.contest(task['contest']['slug']) context.chat_data['contest_slug'] = task['contest']['slug'] context.chat_data['task_id'] = task_id info_txt = msg_formatter.format_chat_info(contest, task) await query.edit_message_text(info_txt, parse_mode='markdown')
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_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="🔥")