예제 #1
0
async def _chan_duckstats(self, chan, context):
    ducc_record = list(ducc_db.find(channel=context))
    total = len(ducc_record)

    if total == 0:
        await self.msg(modname, chan, [f"no duccs were in {context}!"])
        return

    befriended = len([ducc for ducc in ducc_record if ducc["was_killed"] == False])
    murdered = len([ducc for ducc in ducc_record if ducc["was_killed"] == True])
    times = sorted(
        [(ducc["captured"] - ducc["appeared"], ducc["owner"]) for ducc in ducc_record],
        key=lambda i: i[0],
    )
    fastest = times[0]
    slowest = times[-1]

    # Only calculate the average captures of captures done in less than 4 seconds.
    fast_times = [time[0] for time in times if time[0] <= 4]
    average = sum(fast_times) / len(fast_times)

    befriended_str = fmt.bold(fmt.green(befriended))
    murdered_str = fmt.bold(fmt.red(murdered))
    fastest_user_str = fmt.blue(fmt.zwnj(fastest[1]))
    slowest_user_str = fmt.blue(fmt.zwnj(slowest[1]))

    await self.msg(
        modname,
        chan,
        [
            f"duck stats for {context}: {befriended_str} befriended, {murdered_str} murdered. The fastest capture was by {fastest_user_str} in {fastest[0]:,.2f}; the slowest capture was by {slowest_user_str} in {slowest[0]:,.2f}. The average speed of a ducc capture is {average:,.2f} seconds."
        ],
    )
예제 #2
0
파일: sed.py 프로젝트: kiedtl/ircbot
async def filtersed(self, chan, src, msg):
    enabled = configuration.get(self.network, chan, "sed-pattern", cast=bool)
    if not enabled:
        return

    sections = IS_SED_comp.match(msg).groupdict()
    user = sections["user"] or src

    sedinput = None
    if chan in self.backlog and len(self.backlog[chan]):
        backlog = list(reversed(self.backlog[chan]))
        for back_msg in backlog:
            if back_msg[0] == user:
                if IS_SED_LIBERAL.match(back_msg[1]):
                    continue
                if _sed(sections["sed"], back_msg[1]) is sedinput:
                    continue
                sedinput = back_msg[1]
                break

    if not sedinput:
        return

    sedded = _sed(sections["sed"], sedinput)
    user_noping = fmt.zwnj(user)
    await self.message(chan, f"<{user}> {sedded}")
예제 #3
0
async def _user_duckstats(self, chan, user):
    user_noping = fmt.zwnj(user)
    ducc_record = list(ducc_db.find(owner=user))
    total = len(ducc_record)
    channels = _format_items([ducc["channel"] for ducc in ducc_record])

    if total == 0:
        await self.msg(modname, chan, [f"{user} doesn't have any duccs!"])
        return

    befriended = len([ducc for ducc in ducc_record if ducc["was_killed"] == False])
    murdered = len([ducc for ducc in ducc_record if ducc["was_killed"] == True])
    times = sorted([ducc["captured"] - ducc["appeared"] for ducc in ducc_record])
    fastest = times[0]
    slowest = times[-1]

    # Only calculate the average captures of captures done in less than 4 seconds.
    fast_times = [time for time in times if time <= 4]
    average = sum(fast_times) / len(fast_times)

    befriended_str = fmt.bold(fmt.green(befriended))
    murdered_str = fmt.bold(fmt.red(murdered))

    first_message = ""
    if total == 1:
        first_message = f"{user_noping} has captured {total} duccs, befriending {befriended_str} and murdering {murdered_str}."
    else:
        first_message = f"{user_noping} has captured {total} duccs, befriending {befriended_str} and murdering {murdered_str}. Their fastest capture was {fastest:,.2f} seconds, and their slowest capture was {slowest:,.2f} seconds; on average, they capture duccs in about {average:,.2f} seconds."

    await self.msg(
        modname, chan, [first_message, f"{user_noping} has duccs in: {channels}"]
    )
예제 #4
0
async def visit(self, ch, src, msg):
    """
    :name: visit
    :hook: cmd
    :help: water your (or someone else's) botany plant
    :args: @username:str
    :aliases: water
    """

    username = src
    if len(msg) > 1:
        username = msg.split()[0]
    user_noping = fmt.zwnj(username)

    visits_file = VISITORS_FILE.format(username)
    info = {}

    # water the plant by adding ourselves to the end of the recipient's
    # visitors.json file in their homedir
    visitors = []

    try:
        info = _plant_info(username)
        visitors = _plant_visitors(username)
    except FileNotFoundError:
        await self.msg(modname, ch,
                       [f"I couldn't find {user_noping}'s plant :/"])
        return

    is_dead = info["is_dead"]
    description = info["description"]

    # don't bother watering dead plants
    if is_dead:
        await self.ctcp(ch, "ACTION",
                        f"gazes sadly at {user_noping}'s dead {description}")
        return

    visitor = self.nickname
    if username != src:
        if os.path.exists(f"/home/{src}/.botany/"):
            visitor = src

    # just add ourselves to the visitors list. botany will take care of the
    # rest the next time that user opens it.
    visitors.append({"timestamp": int(time.time()), "user": visitor})

    # json.load complains if the file object is write-able
    try:
        with open(visits_file, "w") as fwvisit:
            json.dump(visitors, fwvisit, indent=4)
            await self.ctcp(ch, "ACTION",
                            f"waters {user_noping}'s {description}!")
    except PermissionError:
        await self.ctcp(
            ch,
            "ACTION",
            f"peeks at {user_noping}'s {description} over their garden wall",
        )
예제 #5
0
async def whoami(self, chan, src, msg):
    source = ""
    if not bot_conf.upstream == None:
        source = "".join([fmt.zwnj(i) for i in bot_conf.upstream])

    owner = fmt.zwnj(bot_conf.botmaster)
    email = fmt.zwnj(bot_conf.email[0]) + "‍@‍" + bot_conf.email[1]

    response = bot_conf.rollcall_fmt.format(
        nickname=self.nickname,
        description=bot_conf.description,
        prefix=bot_conf.prefix,
        owner=owner,
        source=source,
        email=email,
    )
    await self.msg(modname, chan, [response])
예제 #6
0
async def fiends(self, chan, src, msg):
    channel = chan
    if len(msg) > 1:
        channel = msg

    chan_duccs = ducc_db.find(channel=channel, was_killed=True)
    owners = [ducc["owner"] for ducc in chan_duccs]
    formatted = _format_items(owners, itemmap=lambda i: fmt.zwnj(i))
    await self.msg(modname, chan, [f"ducc enemies in {chan}: {formatted}"])
예제 #7
0
async def _all_duckstats(self, chan):
    ducc_record = list(ducc_db.find())
    total = len(ducc_record)

    channels = [ducc["channel"] for ducc in ducc_record]
    channels_total = len(utils.dedup(channels))

    channel_frens = [
        ducc["channel"] for ducc in ducc_record if ducc["was_killed"] == False
    ]
    channel_foes = [
        ducc["channel"] for ducc in ducc_record if ducc["was_killed"] == True
    ]

    befriended = len([ducc for ducc in ducc_record if ducc["was_killed"] == False])
    murdered = len([ducc for ducc in ducc_record if ducc["was_killed"] == True])

    times = sorted(
        [
            (ducc["captured"] - ducc["appeared"], ducc["owner"], ducc["channel"])
            for ducc in ducc_record
        ],
        key=lambda i: i[0],
    )
    fastest = times[0]
    slowest = times[-1]
    average = sum([t[0] for t in times]) / len(times)

    befriended_str = fmt.bold(fmt.green(befriended))
    murdered_str = fmt.bold(fmt.red(murdered))
    total_str = fmt.bold(fmt.cyan(total))
    channels_total_str = fmt.yellow(channels_total)
    channels_str = _format_items(channels)
    fastest_user_str = fmt.blue(fmt.zwnj(fastest[1]))
    slowest_user_str = fmt.blue(fmt.zwnj(slowest[1]))

    await self.msg(
        modname,
        chan,
        [
            f"duck stats for {channels_total_str} channels: {befriended_str} befriended, {murdered_str} murdered, {total_str} total. Fastest capture was {fastest[0]:,.2f} by {fastest_user_str} in {fastest[2]}; slowest was {slowest[0]:,.2f} by {slowest_user_str} in {slowest[2]}.",
            f"top channels: {channels_str}",
        ],
    )
예제 #8
0
async def owoify(self, chan, src, msg):
    ms = ""
    try:
        ms = common.get_backlog_msg(self, chan, msg)
    except:
        await self.msg(modname, chan, [f"my backwog is two showt!"])
        return
    usr = fmt.zwnj(ms[0])
    res = _owo_text(ms[1])
    return (Msg.RAW, f"<{usr}> {res}")
예제 #9
0
async def mock(self, chan, src, msg):
    ms = None
    if chan in self.backlog:
        backlog = list(reversed(self.backlog[chan]))
        for back_msg in backlog:
            if back_msg[0] == msg:
                ms = back_msg
                break

    if not ms:
        await self.msg(modname, chan, [f"couldn't find anything to mock"])
        return

    mocked = _mock_text(ms[1])
    usr = fmt.zwnj(ms[0])
    return (Msg.RAW, f"<{usr}> {mocked}")
예제 #10
0
async def pigify(self, c, n, m):
    # pig-latin module (·(oo)·) (・ั(00)・ั)
    #
    # this command is pretty useless, but as it was the first module
    # to be added to this bot, I'm leaving it here for, uh, historical
    # reasons.

    ms = []
    if len(m) > 0:
        ms = [n, m]
    else:
        try:
            ms = common.get_backlog_msg(self, c, m)
        except:
            await self.msg(modname, c,
                           [f"ymay acklogbay isway ootay ortshay!"])
            return

    pigtext = pig.pigify(ms[1])
    pigface = pig.pig_ascii()
    usr = fmt.zwnj(ms[0])

    return (Msg.RAW, f"<{usr}> {pigtext} {pigface}")
예제 #11
0
async def botany(self, ch, src, msg):
    """
    :name: botany
    :hook: cmd
    :help: check on your (or someone else's) botany plant
    :args: @username:str
    """
    username = src
    if len(msg) > 1:
        username = msg.split()[0]
    user_noping = fmt.zwnj(username)

    info = {}
    visitors = []

    try:
        info = _plant_info(username)
        visitors = _plant_visitors(username)
    except FileNotFoundError:
        await self.msg(modname, ch,
                       [f"I couldn't find {user_noping}'s plant :/"])
        return

    description = info["description"]
    info_watered_on = datetime.utcfromtimestamp(info["last_watered"])
    generation = info["generation"]
    score = math.ceil(info["score"])

    # the age string may have fields where the value is only one digit.
    # fix this with a regex to make it palatable to datetime.strptime.
    age_fields = AGE_RE.match(info["age"]).groupdict()
    age_fields2 = {}
    for (name, param) in age_fields.items():
        if param:
            age_fields2[name] = int(param)
    age_delta = timedelta(**age_fields2)

    # when a user is visited, the info file isn't updated; instead, the visitor
    # and visit timestamp is stored in visitors.json. We need to check both of
    # these files (the info file and visitors.json) to find the last time the plant
    # was watered.
    last_visit = datetime.utcfromtimestamp(0)
    last_visitor = None

    if len(visitors) > 0:
        last_visit = datetime.utcfromtimestamp(visitors[-1]["timestamp"])
        last_visitor = visitors[-1]["user"]

    if info_watered_on > last_visit:
        watered_on = info_watered_on
    else:
        watered_on = last_visit

    watered_by_str = ""
    if not last_visitor == None:
        last_visitor_noping = fmt.zwnj(last_visitor)
        watered_by_str = f" by {last_visitor_noping}"

    last_watered = datetime.now() - watered_on
    str_last_watered = format_timedelta(last_watered, locale="en_US")
    str_age = format_timedelta(age_delta, locale="en_US")

    is_dead = False
    if info["is_dead"] or last_watered.days >= 5:
        is_dead = True

    if is_dead:
        await self.msg(modname, ch,
                       [f"{user_noping}'s {description} is dead!"])
    else:
        await self.msg(
            modname,
            ch,
            [
                f"{user_noping}'s {description} was last watered {str_last_watered} ago{watered_by_str}. It has {score:,} points, is {str_age} old, and is on generation {generation}."
            ],
        )