예제 #1
0
파일: builtin.py 프로젝트: xZwop/PCBOT
def game(client: discord.Client, message: discord.Message, name: Annotate.Content=None):
    """ Stop playing or set game to `name`. """
    yield from client.change_status(discord.Game(name=name, type=0))

    if name:
        yield from client.say(message, "*Set the game to* **{}**.".format(name))
    else:
        yield from client.say(message, "*No longer playing.*")
예제 #2
0
파일: builtin.py 프로젝트: xZwop/PCBOT
def disable(client: discord.Client, message: discord.Message, trigger: str.lower):
    """ Disable a command. """
    # If the specified trigger is not in the blacklist, we add it
    if trigger not in lambda_config.data["blacklist"]:
        lambda_config.data["blacklist"].append(trigger)
        lambda_config.save()
        yield from client.say(message, "Command `{}` disabled.".format(trigger))
    else:
        assert trigger in lambdas.data, "Command `{}` does not exist.".format(trigger)

        # The command exists so surely it must be disabled
        yield from client.say(message, "Command `{}` is already disabled.".format(trigger))
예제 #3
0
파일: builtin.py 프로젝트: xZwop/PCBOT
def import_(client: discord.Client, message: discord.Message, module: str, attr: str=None):
    """ Import the specified module. Specifying `attr` will act like `from attr import module`. """
    try:
        import_module(module, attr)
    except ImportError:
        yield from client.say(message, "Unable to import `{}`.".format(module))
    except KeyError:
        yield from client.say(message, "Unable to import `{}` from `{}`.".format(attr, module))
    else:
        # There were no errors when importing, so we add the name to our startup imports
        lambda_config.data["imports"].append((module, attr))
        lambda_config.save()
        yield from client.say(message, "Imported and setup `{}` for import.".format(attr or module))
예제 #4
0
파일: osu.py 프로젝트: xZwop/PCBOT
def pp_(client: discord.Client, message: discord.Message, beatmap_url: str.lower, *options):
    """ Calculate and return the would be pp using `oppai`.

    Options are a parsed set of command-line arguments:  /
    `([acc]% | [num_100s]x100 [num_50s]x50) +[mods] [combo]x [misses]m scorev[scoring_version]`"""
    global last_calc_beatmap

    # This service is only supported on Linux as of yet
    assert platform.system() == "Linux", "This service is unsupported since the bot is not hosted using Linux."

    # Make sure the bot has access to "oppai" lib
    assert os.path.exists(os.path.join(oppai_path, "oppai")), \
        "This service is unavailable until the owner sets up the `oppai` lib."

    # Only download and request when the id is different from the last check
    if last_calc_beatmap["beatmap_id"] not in beatmap_url and last_calc_beatmap["beatmapset_id"] not in beatmap_url:
        # Parse beatmap URL and download the beatmap .osu
        try:
            beatmap = yield from api.beatmap_from_url(beatmap_url)
        except Exception as e:
            yield from client.say(message, e)
            return

        # Download and save the beatmap pp_map.osu
        beatmap_file, _ = yield from utils.download_file(host + "osu/" + str(beatmap["beatmap_id"]))
        with open(os.path.join(oppai_path, "pp_map.osu"), "wb") as f:
            f.write(beatmap_file)
    else:
        beatmap = last_calc_beatmap

    last_calc_beatmap = beatmap

    command_args = [os.path.join(oppai_path, "oppai"), os.path.join(oppai_path, "pp_map.osu")]

    # Add additional options
    if options:
        command_args.extend(options)

    command_stream = Popen(command_args, universal_newlines=True, stdout=PIPE)
    output = command_stream.stdout.read()
    match = re.search(r"(?P<pp>[0-9.e+]+)pp", output)

    # Something went wrong with our service
    assert match, "A problem occurred when parsing the beatmap."

    # We're done! Tell the user how much this score is worth.
    yield from client.say(message, "*{artist} - {title}* **[{version}] {1}** would be worth `{0:,}pp`.".format(
        float(match.group("pp")), " ".join(options), **beatmap))
예제 #5
0
파일: web.py 프로젝트: xZwop/PCBOT
def define(client: discord.Client, message: discord.Message, term: Annotate.LowerCleanContent):
    """ Defines a term using Urban Dictionary. """

    json = yield from utils.download_json("http://api.urbandictionary.com/v0/define", term=term)
    definitions = json["list"] if "list" in json else []

    # Make sure we have something to define
    assert definitions, "Could not define `{}`.".format(term)

    # Send any valid definition (length of message < 2000 characters)
    msg = ""
    for definition in definitions:
        # Format example in code if there is one
        if "example" in definition and definition["example"]:
            definition["example"] = "```{}```".format(definition["example"])

        # Format definition
        msg = "**{}**:\n{}\n{}".format(
            definition["word"],
            definition["definition"],
            definition["example"]
        )

        # If this definition fits in a message, break the loop so that we can send it
        if len(msg) <= 2000:
            break

    # Cancel if the message is too long
    assert len(msg) <= 2000, "Defining this word would be a bad idea."

    # Send the definition
    yield from client.say(message, msg)
예제 #6
0
파일: pokedex.py 프로젝트: xZwop/PCBOT
def filter_type(client: discord.Client, message: discord.Message, slot_1: str.lower, slot_2: str.lower=None):
    matched_pokemon = []
    assert_type(slot_1)

    # Find all pokemon with the matched criteria
    if slot_2:
        assert_type(slot_2)

        # If two slots are provided, search for pokemon with both types matching
        for pokemon in pokedex.values():
            if pokemon["types"] == [slot_1, slot_2]:
                matched_pokemon.append(pokemon["locale_name"])
    else:
        # All pokemon have a type in their first slot, so check if these are equal
        for pokemon in pokedex.values():
            if pokemon["types"][0] == slot_1:
                matched_pokemon.append(pokemon["locale_name"])

    types = [slot_1] if slot_2 is None else [slot_1, slot_2]

    # There might not be any pokemon with the specified types
    assert matched_pokemon, "Looks like there are no pokemon of type **{}**!".format(format_type(types))

    yield from client.say(message, "**Pokemon with type {}**: ```\n{}```".format(
        format_type(types), ", ".join(sorted(matched_pokemon))))
예제 #7
0
파일: osu.py 프로젝트: xZwop/PCBOT
def debug(client: discord.Client, message: discord.Message):
    """ Display some debug info. """
    yield from client.say(message, "Sent `{}` requests since the bot started (`{}`).\n"
                                   "Members registered for update: {}".format(
        api.requests_sent,
        client.time_started.ctime(),
        utils.format_members(*[d["member"] for d in osu_tracking.values()])
    ))
예제 #8
0
파일: osu.py 프로젝트: xZwop/PCBOT
def url(client: discord.Client, message: discord.Message, member: Annotate.Member=Annotate.Self):
    """ Display the member's osu! profile URL. """
    # Member might not be registered
    assert member.id in osu_config.data["profiles"], "No osu! profile assigned to **{}**!".format(member.name)

    # Send the URL since the member is registered
    yield from client.say(message, "**{0.display_name}'s profile:** <https://osu.ppy.sh/u/{1}>".format(
        member, osu_config.data["profiles"][member.id]))
예제 #9
0
파일: builtin.py 프로젝트: xZwop/PCBOT
def unload(client: discord.Client, message: discord.Message, name: str.lower):
    """ Unloads a plugin. """
    assert plugins.get_plugin(name), "`{}` is not a loaded plugin.".format(name)

    # The plugin is loaded so we unload it
    yield from plugins.save_plugin(name)
    plugins.unload_plugin(name)
    yield from client.say(message, "Plugin `{}` unloaded.".format(name))
예제 #10
0
파일: builtin.py 프로젝트: xZwop/PCBOT
def lambda_(client: discord.Client, message: discord.Message):
    """ Create commands. See `{pre}help do` for information on how the code works.

        **In addition**, there's the `arg(i, default=0)` function for getting arguments in positions,
        where the default argument is what to return when the argument does not exist.
        **Owner command unless no argument is specified.**"""
    yield from client.say(message,
                          "**Lambdas:** ```\n" "{}```".format(", ".join(sorted(lambdas.data.keys()))))
예제 #11
0
파일: builtin.py 프로젝트: xZwop/PCBOT
def remove(client: discord.Client, message: discord.Message, trigger: str.lower):
    """ Remove a command. """
    assert trigger in lambdas.data, "Command `{}` does not exist.".format(trigger)

    # The command specified exists and we remove it
    del lambdas.data[trigger]
    lambdas.save()
    yield from client.say(message, "Command `{}` removed.".format(trigger))
예제 #12
0
파일: builtin.py 프로젝트: xZwop/PCBOT
def reload(client: discord.Client, message: discord.Message, name: str.lower=None):
    """ Reloads all plugins or the specified plugin. """
    if name:
        assert plugins.get_plugin(name), "`{}` is not a plugin".format(name)

        # The plugin entered is valid so we reload it
        yield from plugins.save_plugin(name)
        plugins.reload_plugin(name)
        yield from client.say(message, "Reloaded plugin `{}`.".format(name))
    else:
        # Reload all plugins
        yield from plugins.save_plugins()

        for plugin_name in plugins.all_keys():
            plugins.reload_plugin(plugin_name)

        yield from client.say(message, "All plugins reloaded.")
예제 #13
0
파일: builtin.py 프로젝트: xZwop/PCBOT
def load(client: discord.Client, message: discord.Message, name: str.lower):
    """ Loads a plugin. """
    assert not plugins.get_plugin(name), "Plugin `{}` is already loaded.".format(name)

    # The plugin isn't loaded so we'll try to load it
    assert plugins.load_plugin(name), "Plugin `{}` could not be loaded.".format(name)

    # The plugin was loaded successfully
    yield from client.say(message, "Plugin `{}` loaded.".format(name))
예제 #14
0
파일: image.py 프로젝트: xZwop/PCBOT
def resize(client: discord.Client, message: discord.Message,
           url: str, resolution: parse_resolution, *options, extension: str=None):
    """ Resize an image with the given resolution formatted as `<width>x<height>`
    with an optional extension. """
    # Make sure the URL is valid
    try:
        image_bytes, headers = yield from utils.download_file(url)
    except ValueError:
        yield from client.say(message, "The given URL is invalid.")
        return

    match = extension_regex.search(headers["CONTENT-TYPE"])
    assert match, "The given url is not an image."

    # Create some metadata
    image_format = extension or match.group("ext")

    # Set the image upload extension
    extension = image_format.lower()
    if extension.lower() == "jpeg":
        extension = "jpg"
    if image_format.lower() == "jpg":
        image_format = "JPEG"

    filename = "{}.{}".format(message.author.display_name, extension)

    # Open the image in Pillow
    image = Image.open(BytesIO(image_bytes))
    image = image.resize(resolution, Image.NEAREST if "-nearest" in options else Image.ANTIALIAS)

    # Upload the image
    buffer = BytesIO()
    try:
        image.save(buffer, image_format)
    except KeyError as e:
        yield from client.say(message, "Image format `{}` is unsupported.".format(e))
        return
    except Exception as e:
        yield from client.say(message, str(e) + ".")
        return
    buffer.seek(0)

    yield from client.send_file(message.channel, buffer, filename=filename)
예제 #15
0
파일: builtin.py 프로젝트: xZwop/PCBOT
def eval_(client: discord.Client, message: discord.Message, python_code: Annotate.Code):
    """ Evaluate a python expression. Can be any python code on one line that returns something. """
    code_globals.update(dict(message=message, client=client))

    try:
        result = eval(python_code, code_globals)
    except Exception as e:
        result = utils.format_exception(e)

    yield from client.say(message, "**Result:** \n```{}\n```".format(result))
예제 #16
0
파일: builtin.py 프로젝트: xZwop/PCBOT
def setowner(client: discord.Client, message: discord.Message):
    """ Set the bot owner. Only works in private messages. """
    if not message.channel.is_private:
        return

    assert not utils.owner_cfg.data, "An owner is already set."

    owner_code = str(random.randint(100, 999))
    logging.critical("Owner code for assignment: {}".format(owner_code))

    yield from client.say(message,
                                 "A code has been printed in the console for you to repeat within 60 seconds.")
    user_code = yield from client.wait_for_message(timeout=60, channel=message.channel, content=owner_code)

    assert user_code, "You failed to send the desired code."

    if user_code:
        yield from client.say(message, "You have been assigned bot owner.")
        utils.owner_cfg.data = message.author.id
        utils.owner_cfg.save()
예제 #17
0
파일: builtin.py 프로젝트: xZwop/PCBOT
def ping(client: discord.Client, message: discord.Message):
    """ Tracks the time spent parsing the command and sending a message. """
    # Track the time it took to receive a message and send it.
    start_time = datetime.now()
    first_message = yield from client.say(message, "Pong!")
    stop_time = datetime.now()

    # Edit our message with the tracked time (in ms)
    time_elapsed = (stop_time - start_time).microseconds / 1000
    yield from client.edit_message(first_message,
                                   "Pong! `{elapsed:.4f}ms`".format(elapsed=time_elapsed))
예제 #18
0
파일: osu.py 프로젝트: xZwop/PCBOT
def unlink(client: discord.Client, message: discord.Message, member: Annotate.Member=Annotate.Self):
    """ Unlink your osu! account or unlink the member specified (**Owner only**). """
    # The message author is allowed to unlink himself
    # If a member is specified and the member is not the owner, set member to the author
    if not utils.is_owner(message.author):
        member = message.author

    # The member might not be linked to any profile
    assert member.id in osu_config.data["profiles"], "No osu! profile assigned to **{}**!".format(member.name)

    # Unlink the given member (usually the message author)
    del osu_config.data["profiles"][member.id]
    osu_config.save()
    yield from client.say(message, "Unlinked **{}'s** osu! profile.".format(member.name))
예제 #19
0
파일: pokedex.py 프로젝트: xZwop/PCBOT
def egg(client: discord.Client, message: discord.Message, egg_type: Annotate.LowerCleanContent):
    """ Get the pokemon hatched from the specified egg_type
    (in distance, e.g. 2 or 5km) """
    # Strip any km suffix (or prefix, whatever)
    egg_type = egg_type.replace("km", "")

    try:
        distance = int(float(egg_type))  # Using float for anyone willing to type 2.0km
    except ValueError:
        yield from client.say(message, "The egg type **{}** is invalid.".format(egg_type))
        return

    pokemon_criteria = []
    egg_types = []

    # Find all pokemon with the specified distance
    for pokemon in sorted(pokedex.values(), key=itemgetter("id")):
        # We've exceeded the generation and no longer need to search
        if pokemon["generation"] not in pokemon_go_gen:
            break

        if "hatches_from" not in pokemon:
            continue

        if pokemon["hatches_from"] not in egg_types:
            egg_types.append(pokemon["hatches_from"])

        if pokemon["hatches_from"] == distance:
            pokemon_criteria.append(pokemon["locale_name"])

    # The list might be empty
    assert pokemon_criteria, "No pokemon hatch from a **{}km** egg. **Valid distances are** ```\n{}```".format(
        distance, ", ".join("{}km".format(s) for s in sorted(egg_types)))

    # Respond with the list of matching criteria
    yield from client.say(message, "**The following Pokémon may hatch from a {}km egg**:```\n{}```".format(
        distance, ", ".join(sorted(pokemon_criteria))))
예제 #20
0
파일: builtin.py 프로젝트: xZwop/PCBOT
def help_(client: discord.Client, message: discord.Message, command: str.lower=None, *args):
    """ Display commands or their usage and description. """
    # Display the specific command
    if command:
        if command.startswith(config.command_prefix):
            command = command[1:]

        for plugin in plugins.all_values():
            cmd = plugins.get_command(plugin, command)
            if not cmd:
                continue

            # Get the specific command with arguments and send the help
            cmd = plugins.get_sub_command(cmd, args)
            yield from client.say(message, utils.format_help(cmd))
            break

    # Display every command
    else:
        commands = []

        for plugin in plugins.all_values():
            if getattr(plugin, "__commands", False):  # Massive pile of shit that works (so sorry)
                commands.extend(
                    cmd.name_prefix.split()[0] for cmd in plugin.__commands
                    if not cmd.hidden and
                    (not getattr(getattr(cmd, "function"), "__owner__", False) or
                     utils.is_owner(message.author))
                )

        commands = ", ".join(sorted(commands))

        m = "**Commands**:```{0}```Use `{1}help <command>`, `{1}<command> {2}` or " \
            "`{1}<command> {3}` for command specific help.".format(
            commands, config.command_prefix, *config.help_arg)
        yield from client.say(message, m)
예제 #21
0
파일: osu.py 프로젝트: xZwop/PCBOT
def gamemode(client: discord.Client, message: discord.Message, mode: api.GameMode.get_mode):
    """ Set the gamemode for the specified member.

    Gamemodes are `Standard`, `Taiko`, `CTB` and `Mania`. """
    assert message.author.id in osu_config.data["profiles"], \
        "No osu! profile assigned to **{}**!".format(message.author.name)

    osu_config.data["mode"][message.author.id] = mode.value
    osu_config.save()

    # Clear the scores when changing mode
    if message.author.id in osu_tracking:
        del osu_tracking[message.author.id]

    yield from client.say(message, "Set your gamemode to **{}**.".format(mode.name))
예제 #22
0
파일: osu.py 프로젝트: xZwop/PCBOT
def link(client: discord.Client, message: discord.Message, name: Annotate.LowerContent):
    """ Tell the bot who you are on osu!. """
    osu_user = yield from api.get_user(u=name)

    # Check if the osu! user exists
    assert osu_user, "osu! user `{}` does not exist.".format(name)

    # Clear the scores when changing user
    if message.author.id in osu_tracking:
        del osu_tracking[message.author.id]

    # Assign the user using their unique user_id
    osu_config.data["profiles"][message.author.id] = osu_user["user_id"]
    osu_config.data["mode"][message.author.id] = api.GameMode.Standard.value
    osu_config.save()
    yield from client.say(message, "Set your osu! profile to `{}`.".format(osu_user["username"]))
예제 #23
0
파일: builtin.py 프로젝트: xZwop/PCBOT
def bot_info(client: discord.Client, message: discord.Message):
    """ Display basic information and changelog. """
    # Grab the latest commit
    # changelog = yield from get_changelog(1)

    yield from client.say(message, "**{ver}** - **{name}**\n"
                                   "__Github repo:__ <{repo}>\n"
                                   "__Owner (host):__ `{host}`\n"
                                   "__Up since:__ `{up}`\n"
                                   "__Messages since up date:__ `{mes}`\n"
                                   "__Servers connected to:__ `{servers}`".format(
        ver=config.version, name=client.user.name,
        up=client.time_started.strftime("%d-%m-%Y %H:%M:%S"), mes=len(client.messages),
        host=getattr(utils.get_member(client, utils.owner_cfg.data), "name", None) or "Not in this server.",
        servers=len(client.servers),
        repo="https://github.com/{}".format(config.github_repo),
        #  changelog=changelog
    ))
예제 #24
0
파일: osu.py 프로젝트: xZwop/PCBOT
def osu(client: discord.Client, message: discord.Message, member: Annotate.Member=Annotate.Self):
    """ Handle osu! commands.

    When your user is linked, this plugin will check if you are playing osu!
    (your profile would have `playing osu!`), and send updates whenever you set a
    new top score. """
    # Make sure the member is assigned
    assert member.id in osu_config.data["profiles"], "No osu! profile assigned to **{}**!".format(member.name)

    user_id = osu_config.data["profiles"][member.id]

    # Set the signature color to that of the role color
    color = "pink" if member.color == discord.Color.default() \
        else "#{0:02x}{1:02x}{2:02x}".format(*member.color.to_tuple())

    # Download and upload the signature
    signature, _ = yield from utils.download_file("http://lemmmy.pw/osusig/sig.php",
                                                  colour=color, uname=user_id, pp=True,
                                                  countryrank=True, xpbar=True, mode=get_mode(member.id).value)
    yield from client.send_file(message.channel, signature, filename="sig.png")

    yield from client.say(message, "<https://osu.ppy.sh/u/{}>".format(user_id))
예제 #25
0
파일: pokedex.py 프로젝트: xZwop/PCBOT
def scalefactor(client: discord.Client, message: discord.Message, factor: float=default_scale_factor):
    """ Set the image scaling factor for your server. If no factor is given, the default is set. /
    **This command requires the `Manage Server` permission.**"""
    assert factor <= max_scale_factor, "The factor **{}** is too high **(max={})**.".format(
        factor, max_scale_factor)
    assert min_scale_factor <= factor, "The factor **{}** is too low **(min={})**.".format(
        factor, min_scale_factor)

    if message.server.id not in pokedex_config.data:
        pokedex_config.data[message.server.id] = {}

    # Handle specific scenarios
    if factor == default_scale_factor:
        if "scale-factor" in pokedex_config.data[message.server.id]:
            del pokedex_config.data[message.server.id]["scale-factor"]
            reply = "Pokédex image scale factor reset to **{factor}**."
        else:
            reply = "Pokédex image scale factor is **{factor}**."
    else:
        pokedex_config.data[message.server.id]["scale-factor"] = factor
        reply = "Pokédex image scale factor set to **{factor}**."

    pokedex_config.save()
    yield from client.say(message, reply.format(factor=factor))
예제 #26
0
파일: builtin.py 프로젝트: xZwop/PCBOT
def plugin_(client: discord.Client, message: discord.Message):
    """ Manage plugins.
        **Owner command unless no argument is specified.** """
    yield from client.say(message,
                          "**Plugins:** ```{}```".format(", ".join(plugins.all_keys())))
예제 #27
0
파일: builtin.py 프로젝트: xZwop/PCBOT
def stop(client: discord.Client, message: discord.Message):
    """ Stops the bot. """
    yield from client.say(message, ":boom: :gun:")
    yield from plugins.save_plugins()
    yield from client.logout()
예제 #28
0
파일: builtin.py 프로젝트: xZwop/PCBOT
def add(client: discord.Client, message: discord.Message, trigger: str.lower, python_code: Annotate.Code):
    """ Add a command that runs the specified python code. """
    lambdas.data[trigger] = python_code
    lambdas.save()
    yield from client.say(message, "Command `{}` set.".format(trigger))
예제 #29
0
파일: builtin.py 프로젝트: xZwop/PCBOT
def changelog_(client: discord.Client, message: discord.Message, num: utils.int_range(f=1)=3):
    """ Get `num` requests from the changelog. Defaults to 3. """
    changelog = yield from get_changelog(num)
    yield from client.say(message, changelog)
예제 #30
0
파일: builtin.py 프로젝트: xZwop/PCBOT
def source(client: discord.Client, message: discord.Message, trigger: str.lower):
    """ Disable source of a command """
    assert trigger in lambdas.data, "Command `{}` does not exist.".format(trigger)

    # The command exists so we display the source
    yield from client.say(message, "Source for `{}`:\n{}".format(trigger, lambdas.data[trigger]))