Beispiel #1
0
    async def report_battle_events(self):
        await self.wait_until_ready()
        while not self.is_closed():
            try:
                r = get_battle_page()
                if not isinstance(r.get("battles"), dict):
                    sleep_seconds = r.get("last_updated") + 60 - timestamp()
                    await asyncio.sleep(
                        sleep_seconds if sleep_seconds > 0 else 0)
                    continue

                desc = "'Empty' medals are being guessed based on the division wall. Expect false-positives!"
                empty_divisions = {
                    1:
                    discord.Embed(
                        title="Possibly empty **__last-minute__ D1** medals",
                        description=desc),
                    2:
                    discord.Embed(
                        title="Possibly empty **__last-minute__ D2** medals",
                        description=desc),
                    3:
                    discord.Embed(
                        title="Possibly empty **__last-minute__ D3** medals",
                        description=desc),
                    4:
                    discord.Embed(
                        title="Possibly empty **__last-minute__ D4** medals",
                        description=desc),
                    11:
                    discord.Embed(
                        title="Possibly empty **__last-minute__ Air** medals",
                        description=desc),
                }
                for kind, div, data in check_battles(r.get("battles")):
                    if kind == "epic" and not DB.check_epic(data["div_id"]):
                        embed_data = dict(
                            title=" ".join(
                                data["extra"]["intensity_scale"].split(
                                    "_")).title(),
                            url=data["url"],
                            description=
                            f"Epic battle {' vs '.join(data['sides'])}!\nBattle for {data['region']}, Round {data['zone_id']}",
                            footer=f"Round time {data['round_time']}",
                        )
                        embed = discord.Embed.from_dict(embed_data)
                        logger.debug(f"{embed_data=}")
                        for channel_id in DB.get_kind_notification_channel_ids(
                                "epic"):
                            if role_id := DB.get_role_id_for_channel_division(
                                    kind="epic",
                                    channel_id=channel_id,
                                    division=div):
                                await self.get_channel(channel_id).send(
                                    f"<@&{role_id}> epic battle detected!",
                                    embed=embed)
                            else:
                                await self.get_channel(channel_id).send(
                                    embed=embed)
                        DB.add_epic(data["div_id"])

                    if kind == "empty" and data[
                            "round_time_s"] >= 85 * 60 and not DB.check_empty_medal(
                                data["div_id"]):
                        empty_divisions[div].add_field(
                            name=
                            f"**Battle for {data['region']} {' '.join(data['sides'])}**",
                            value=
                            f"[R{data['zone_id']} | Time {data['round_time']}]({data['url']})"
                        )
                        DB.add_empty_medal(data["div_id"])
                for d, e in empty_divisions.items():
                    if e.fields:
                        for channel_id in DB.get_kind_notification_channel_ids(
                                "empty"):
                            if role_id := DB.get_role_id_for_channel_division(
                                    kind="empty",
                                    channel_id=channel_id,
                                    division=d):
                                await self.get_channel(channel_id).send(
                                    f"<@&{role_id}> empty medals in late rounds!",
                                    embed=e)
                            else:
                                await self.get_channel(channel_id).send(embed=e
                                                                        )
                sleep_seconds = r.get("last_updated") + 60 - timestamp()
                await asyncio.sleep(sleep_seconds if sleep_seconds > 0 else 0)
Beispiel #2
0
    async def report_rss_events(self):
        await self.wait_until_ready()
        feed_response = None
        while not self.is_closed():
            try:
                for country in COUNTRIES.values():
                    latest_ts = DB.get_rss_feed_timestamp(country.id)
                    rss_link = f"https://www.erepublik.com/en/main/news/military/all/{country.link}/1/rss"
                    feed_response = requests.get(rss_link)
                    feed_response.raise_for_status()
                    for entry in reversed(
                            feedparser.parse(feed_response.text).entries):
                        entry_ts = time.mktime(entry["published_parsed"])
                        entry_link = entry["link"]
                        # Check if event timestamp is after latest processed event for country
                        if entry_ts > latest_ts:
                            DB.set_rss_feed_timestamp(country.id, entry_ts)
                            title = text = ""
                            msg = entry["summary"]
                            dont_send = False
                            for kind in events:
                                match = kind.regex.search(msg)
                                if match:
                                    values = match.groupdict()
                                    # Special case for Dictator/Liberation wars
                                    if "invader" in values and not values[
                                            "invader"]:
                                        values["invader"] = values["defender"]

                                    # Special case for resource concession
                                    if "link" in values:
                                        __link = values["link"]
                                        entry_link = __link if __link.startswith(
                                            "http"
                                        ) else f"https://www.erepublik.com{__link}"
                                        logger.debug(
                                            kind.format.format(**dict(
                                                match.groupdict(), **{
                                                    "current_country":
                                                    country.name
                                                })))
                                        logger.debug(entry_link)
                                    is_latvia = country.id == 71
                                    has_latvia = any("Latvia" in v
                                                     for v in values.values())
                                    if is_latvia or has_latvia:
                                        text = kind.format.format(**dict(
                                            match.groupdict(), **
                                            {"current_country": country.name}))
                                        title = kind.name
                                    else:
                                        dont_send = True
                                    break
                            else:
                                logger.warning(
                                    f"Unable to parse: {str(entry)}")
                                continue

                            if dont_send:
                                continue

                            entry_datetime = datetime.datetime.fromtimestamp(
                                entry_ts, pytz.timezone("US/Pacific"))
                            embed = discord.Embed(title=title,
                                                  url=entry_link,
                                                  description=text)
                            embed.set_author(
                                name=country.name,
                                icon_url=
                                f"https://www.erepublik.com/images/flags/L/{country.link}.gif"
                            )
                            embed.set_footer(
                                text=
                                f"{entry_datetime.strftime('%F %T')} (eRepublik time)"
                            )

                            logger.debug(f"Message sent: {text}")
                            for channel_id in DB.get_kind_notification_channel_ids(
                                    "events"):
                                await self.get_channel(channel_id).send(
                                    embed=embed)
            except Exception as e:
                logger.error("eRepublik event reader ran into a problem!",
                             exc_info=e)
                try:
                    with open(f"debug/{timestamp()}.rss", "w") as f:
                        f.write(feed_response.text)
                except (NameError, AttributeError):
                    logger.error("There was no Response object!", exc_info=e)
            finally:
                await asyncio.sleep((timestamp() // 300 + 1) * 300 -
                                    timestamp())
Beispiel #3
0
async def control(ctx: commands.Context, command: str, *args):
    _process_member(ctx.message.author)
    if command == "register":
        return await control_register(ctx, *args)
    if command in ["notify", "unnotify"]:
        if ctx.channel.type == ChannelType.private:
            return await ctx.send(MESSAGES["not_in_pm"])
        if not ctx.author.guild_permissions.administrator:
            return await ctx.send(MESSAGES["not_admin"])
        if not args:
            return await ctx.send(
                f"❌ Please provide what kind of notifications You would like to {'en' if command == 'notify' else 'dis'}able! Currently available: {', '.join(NOTIFICATION_KINDS)}"
            )
        kind = str(args[0]).lower()
        if kind not in NOTIFICATION_KINDS:
            return await ctx.send(
                f'❌ Notification {kind=} is unknown! Currently available: {", ".join(NOTIFICATION_KINDS)}'
            )
        if command == "notify":
            return await control_notify(ctx, kind)
        if command == "unnotify":
            return await control_unnotify(ctx, kind)

    if command == "mention":
        if ctx.channel.type == ChannelType.private:
            return await ctx.send(MESSAGES["not_in_pm"])
        if not ctx.author.guild_permissions.administrator:
            return await ctx.send(MESSAGES["not_admin"])
        if not args or not 3 <= len(args) <= 4:
            return await ctx.send(
                MESSAGES["mention_help"].format(command=command))

        try:
            kind, action, division, *role = args
            if role:
                role = role[0]
            kind = str(kind).lower()
            if ctx.channel.id not in DB.get_kind_notification_channel_ids(
                    kind):
                return await ctx.send(MESSAGES["only_registered_channels"])
            if kind not in ("epic", "empty"):
                return await ctx.send(
                    f"❌ {kind=} doesn't support division mentioning!")

            if action not in ("set", "remove"):
                return await ctx.send(
                    MESSAGES["mention_help"].format(command=command))
            action = str(action).lower()
            division = str(division).title()
            if division not in DIVISION_MAPPING:
                await ctx.send(
                    f"❌ Unknown {division=}! Available divisions: {', '.join(d.title() for d in DIVISION_MAPPING.keys())}"
                )
                return await ctx.send(
                    MESSAGES["mention_info"].format(kind=kind))

            if action == "set":
                return await control_mention_set(ctx, kind, division, role)
            if action == "remove":
                return await control_mention_remove(ctx, kind, division)
        except Exception as e:
            logger.warning(str(e), exc_info=e, stacklevel=3)
            return await ctx.send(
                MESSAGES["mention_help"].format(command=command))

    if command == "exit":
        if ctx.author.id == ADMIN_ID:
            await ctx.send(f"{ctx.author.mention} Bye!")
            sys.exit(0)
    return await ctx.send(f"❌ Unknown {command=}!")