Пример #1
0
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)
Пример #2
0
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)
Пример #3
0
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)
Пример #4
0
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)
Пример #5
0
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="🔥")
Пример #6
0
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)