Пример #1
0
def add_manuals(bot):
    """Reads all manuals in the config folder and adds them to the bot."""
    manual_order = []
    directory = bot.path + '/config/'
    for plugin in bot.plugins:
        try:
            with open(directory + plugin + '-manual.json', 'r') as manual_file:
                loaded_manual = (plugin, json.load(manual_file))
            if 'entries' not in loaded_manual[1]:
                raise BotException(
                    EXCEPTION,
                    "The manual for plugin {} has no entries.".format(plugin))
            if 'order' not in loaded_manual[1]:
                raise BotException(
                    EXCEPTION,
                    "The manual for plugin {} has no order.".format(plugin))
            for entry in loaded_manual[1]['order']:
                if entry not in loaded_manual[1]['entries']:
                    raise BotException(
                        EXCEPTION, "The manual for plugin {0} is missing "
                        "the entry {1}.".format(plugin, entry))
            if plugin == 'base':
                bot.manuals.append(loaded_manual)
            else:
                manual_order.append(loaded_manual)
        except FileNotFoundError:
            if plugin == 'base':
                raise BotException(EXCEPTION,
                                   "The base manual was not found.",
                                   error_type=ErrorTypes.STARTUP)
            else:
                pass
    bot.manuals += sorted(manual_order)
Пример #2
0
def add_configurations(bot):
    configurations_list = {}
    directory = bot.path + '/config/'
    try:
        with open(directory + 'config.json', 'r') as config_file:
            configurations_list['core'] = json.load(config_file)
    except Exception as e:
        raise BotException(EXCEPTION,
                           "Could not open the core configuration file",
                           e=e,
                           error_type=ErrorTypes.STARTUP)

    for plugin in bot.plugins:
        try:
            with open(directory + plugin + '.json', 'r') as config_file:
                configurations_list[plugin] = json.load(config_file)
        except FileNotFoundError:
            module = bot.plugins[plugin][0]
            if (getattr(module, 'uses_configuration', False)
                    and module.uses_configuration):
                raise BotException(EXCEPTION,
                                   "Plugin {} requires a configuration file, "
                                   "but it was not found.".format(plugin),
                                   error_type=ErrorTypes.STARTUP)
        except Exception as e:
            raise BotException(
                EXCEPTION,
                "Could not open the {} configuration file.".format(plugin),
                e=e,
                error_type=ErrorTypes.STARTUP)

    bot.configurations = configurations_list
    return configurations_list
Пример #3
0
def get_channel(bot,
                identity,
                server=None,
                attribute=None,
                safe=False,
                strict=False):
    """Like get_member(), but gets the channel instead."""
    if identity.startswith('<#') and identity.endswith('>'):
        identity = identity.strip('<#>')
    if server is None:
        channels = bot.get_all_channels()
    else:
        channels = server.channels
    result = discord.utils.get(channels, id=identity)
    if result is None:
        result = discord.utils.get(channels, name=identity)

    if result:
        if attribute:
            if hasattr(result, attribute):
                return getattr(result, attribute)
            elif safe:
                return None
            else:
                raise BotException(
                    EXCEPTION, "Invalid attribute, '{}'.".format(attribute))
        else:
            return result
    else:
        if safe:
            return None
        else:
            raise BotException(EXCEPTION, "{} not found.".format(identity))
Пример #4
0
def guess_index(bot, text, safe=True):
    """Guesses the closest command and returns the base and index."""
    if not text:
        if safe:
            return (None, -1)
        else:
            raise BotException(EXCEPTION, "No guess text.")
    text = text.strip()
    split_content = text.split(' ', 1)
    if len(split_content) == 1:
        split_content.append('')
    base, parameters = split_content
    base = base.lower()
    try:
        command = bot.commands[base]
    except KeyError:
        if safe:
            return (None, -1)
        else:
            raise BotException(EXCEPTION, "Invalid base.")
    parameters, quoted_indices = split_parameters(parameters, quote_list=True)
    return (base,
            match_blueprint(bot,
                            base,
                            parameters,
                            quoted_indices,
                            command,
                            find_index=True))
Пример #5
0
def get_configurations(bot):
    configurations_list = {}
    directory = bot.path + '/config'
    try:
        with open(directory + '/config.json', 'r') as config_file:
            configurations_list['core'] = json.load(config_file)
    except Exception as e:
        raise BotException(ErrorTypes.STARTUP,
                           EXCEPTION,
                           "Could not open the core configuration file",
                           e=e)

    directory += '/'
    for plugin in bot.plugins:
        try:
            with open(directory + plugin + '.json', 'r') as config_file:
                configurations_list[plugin] = json.load(config_file)
        except FileNotFoundError:
            if (getattr(bot.plugins[plugin][0], 'uses_configuration', False)
                    and bot.plugins[plugin][0].uses_configuration):
                raise BotException(
                    ErrorTypes.STARTUP, EXCEPTION,
                    "Plugin " + plugin + " requires a configuration file, "
                    "but it was not found.")
        except Exception as e:
            raise BotException(ErrorTypes.STARTUP,
                               EXCEPTION,
                               "Could not open the " + plugin +
                               " configuration file.",
                               e=e)

    return configurations_list
Пример #6
0
def fill_shortcut(bot, shortcut, base, parameters, server=None):
    """
    Replaces elements in the syntax using the template with the parameters.
    Example:
        (<('create {} {}', ':^')>, 'tag', '"my tag" tag text'])
    Returns:
        'create "my tag" tag text'
    """
    parameters = split_parameters(parameters, include_quotes=True)
    parameters_length = len(parameters)
    base_index = shortcut.bases.index(base)
    syntax, template = shortcut.format_pairs[base_index]

    if not template:
        if parameters:
            raise BotException(
                EXCEPTION,
                "Shortcut requires no arguments, but some were given.",
                commands.usage_reminder(bot,
                                        base,
                                        index=base_index,
                                        shortcut=True,
                                        server=server))
        return syntax

    try:
        current = 0
        to_add = []
        for argument_type in template:
            while (current < parameters_length
                   and parameters[current].isspace()):
                current += 1

            if argument_type == ':':
                to_add.append(parameters[current])

            elif argument_type in ('&', '#'):
                to_add.append(''.join(parameters[current:]))

            elif argument_type in ('^', '+'):
                if len(parameters[current:]) == 1 and argument_type == '^':
                    combined = parameters[current]
                else:
                    combined = ''.join(parameters[current:])
                assert combined
                to_add.append(combined)

            current += 1

        syntax = syntax.format(*to_add)
    except:
        reminder = commands.usage_reminder(bot,
                                           base,
                                           index=base_index,
                                           shortcut=True,
                                           server=server)
        raise BotException(EXCEPTION, "Invalid shortcut syntax.", reminder)

    return syntax
Пример #7
0
async def join_and_ready(bot,
                         voice_channel,
                         include_player=False,
                         is_mod=False,
                         reconnect=False):
    """Joins the voice channel and stops any player if it exists.

    Returns the voice_client object from bot.join_voice_channel.
    If include_player is True, this will return a tuple of both the voice
    client and the player (None if not found).
    """
    server = voice_channel.server
    muted = voice_channel.id in data.get(bot,
                                         'base',
                                         'muted_channels',
                                         server_id=server.id,
                                         default=[])
    if voice_channel == server.afk_channel:
        raise BotException(EXCEPTION, "This is the AFK channel.")
    if muted and not is_mod:
        raise BotException(EXCEPTION,
                           "The bot is muted in this voice channel.")
    if reconnect:
        await leave_and_stop(bot, server)
    if not bot.is_voice_connected(server):
        try:
            voice_client = await bot.join_voice_channel(voice_channel)
        except Exception as e:
            raise BotException(EXCEPTION,
                               "Failed to join the voice channel.",
                               e=e)
    else:
        voice_client = bot.voice_client_in(server)
        if voice_client.channel != voice_channel:
            try:
                await voice_client.move_to(voice_channel)
            except Exception as e:
                raise BotException(EXCEPTION,
                                   "Failed to move to the voice channel.",
                                   e=e)

    player = get_player(bot, server.id)
    if player is not None:
        if player.is_playing():
            player.stop()
        elif not player.is_done():  # Can this even happen?
            raise BotException(EXCEPTION,
                               "Audio is pending, please try again later.")

    if include_player:
        return (voice_client, player)
    else:
        return voice_client
Пример #8
0
def add_plugins(bot):
    """
    Gets a list of all of the plugins and stores them as a key/value pair of
    the plugin name and the module itself (renamed to plugin for the user).
    In addition, this also sets the commands given by each plugin.
    """
    directory = '{}/plugins'.format(bot.path)
    data_directory = '{}/plugins/plugin_data'.format(bot.path)
    if os.path.isdir(data_directory):
        logging.debug("Setting plugin_data as plugin import path.")
        sys.path.append(data_directory)
    try:
        plugins_list = os.listdir(directory)
    except FileNotFoundError:
        raise BotException(EXCEPTION,
                           "Plugins directory not found",
                           error_type=ErrorTypes.STARTUP)
    valid_plugins = {}

    # Add base plugin
    from jshbot import base
    plugin_commands = base.get_commands()
    commands.add_commands(bot, plugin_commands, base)
    valid_plugins['base'] = [base, plugin_commands]

    # Get plugin commands
    for plugin in plugins_list:
        if (plugin[0] in ('.', '_') or plugin == 'base'
                or not plugin.endswith('.py')):
            continue
        try:
            spec = importlib.util.spec_from_file_location(
                plugin, '{}/{}'.format(directory, plugin))
            module = importlib.util.module_from_spec(spec)
            spec.loader.exec_module(module)
            plugin_commands = module.get_commands()
            commands.add_commands(bot, plugin_commands, module)
        except Exception as e:
            traceback.print_exc()
            raise BotException(EXCEPTION,
                               "Failed to import external plugin",
                               plugin,
                               e=e,
                               error_type=ErrorTypes.STARTUP)
        else:
            logging.debug("Adding plugin {}".format(plugin))
            valid_plugins[plugin] = [module, plugin_commands]

    if len(valid_plugins):
        logging.debug("Loaded {} plugin(s)".format(len(valid_plugins)))

    bot.plugins = valid_plugins
Пример #9
0
def fill_shortcut(bot, parameters, blueprint, modifiers):
    '''
    Replaces elements in the blueprint with the modifiers specified.
    Example: fill_shortcut('"my tag" tag text', 'tag -create {} {}', ':^')
    Returns: ('tag', '-create "my tag" tag text')
    '''

    # Split parameters
    split = re.split('( +)', parameters)
    split.append('-')

    it = 0
    format_list = []
    for modifier in modifiers:  # :^&+#

        if modifier == ':':  # Insert single argument
            block, it = get_argument_block(split, it, get_all=True)
            if not block or block == '-':
                it = -1  # Set error
                break
            format_list.append('"' + block + '"')
        else:  # Insert remaining trailing arguments
            remaining = ''
            while it < len(split) - 1:
                if modifier in ['^', '&']:  # Single
                    remaining += split[it]
                else:  # Split
                    block, it = get_argument_block(split, it, get_all=True)
                    remaining += '"' + block + '" '
                it += 1
            format_list.append(remaining.strip())
        it += 1

    if it < len(split) - 1:
        base = blueprint.split(' ', 1)[0]
        raise BotException(ErrorTypes.RECOVERABLE, EXCEPTION,
                           "Invalid syntax.", bot.usage_reminder(base))

    # Check for modifiers length mismatch
    if len(modifiers) == 0 and len(split) - 2:
        raise BotException(
            ErrorTypes.RECOVERABLE, EXCEPTION,
            "Shortcut requires no arguments, but some were given.")

    # Insert elements from the format list
    filled_blueprint = blueprint.format(*format_list)
    blueprint_split = filled_blueprint.split(' ', 1)
    if len(blueprint_split) == 1:
        blueprint_split.append('')
    return blueprint_split
Пример #10
0
def list_data_remove(bot,
                     plugin_name,
                     key,
                     value=None,
                     server_id=None,
                     channel_id=None,
                     user_id=None,
                     default=None,
                     safe=False,
                     volatile=False):
    """Remove data from list at location.

    Works like remove, but manipulates the list at the location. If the value
    is not specified, it will pop the first element.
    """
    current, location_key = get_location(bot, server_id, channel_id, user_id,
                                         volatile)
    if (not current or plugin_name not in current
            or key not in current[plugin_name]):
        if safe:
            return default
        else:
            raise BotException(EXCEPTION, "Key '{}' not found.".format(key))
    current = current[plugin_name][key]
    if type(current) is not list:
        if safe:
            return default
        else:
            raise BotException(EXCEPTION, "Data is not a list.")
    elif not current:  # Empty, can't pop
        if safe:
            return default
        else:
            raise BotException(EXCEPTION, "List is empty.")

    if not volatile and location_key not in bot.data_changed:
        bot.data_changed.append(location_key)
    if value is None:
        return current.pop()
    else:  # Pop value
        if value not in current:
            if safe:
                return default
            else:
                raise BotException(
                    EXCEPTION, "Value '{}' not found in list.".format(value))
        else:
            current.remove(value)
            return value
Пример #11
0
def get_random_line(bot, name):
    '''
    Gets a random line in the file given by the name argument.
    '''
    file_path = bot.path + '/data/simple_bot_manager.py/' + name
    try:
        if os.stat(file_path).st_size > 0:
            with open(file_path, 'r') as data_file:
                return str(random.choice(list(data_file))).rstrip()
        else:
            raise BotException(ErrorTypes.RECOVERABLE, EXCEPTION,
                    "The {} file is empty.".format(name))
    except:
        raise BotException(ErrorTypes.RECOVERABLE, EXCEPTION,
                "The {} file was not found.".format(name))
Пример #12
0
def delete_temporary_file(bot, filename, safe=True):
    """Deletes the given file from the temp folder."""
    try:
        os.remove('{0}/temp/{1}'.format(bot.path, filename))
    except Exception as e:
        if not safe:
            raise BotException(EXCEPTION, "File could not be deleted.", e=e)
Пример #13
0
def remove(bot,
           plugin_name,
           key,
           server_id=None,
           channel_id=None,
           user_id=None,
           default=None,
           safe=False,
           volatile=False):
    """Removes the given key from the specified location.

    If the key does not exist and the safe flag is not set, this will throw an
    exception. If the safe flag is set, it will return default. Otherwise, this
    will return the found value, and remove it from the dictionary.

    If the key is None, it removes all of the data associated with that plugin
    for the given location. Use with caution.
    """
    current, location_key = get_location(bot, server_id, channel_id, user_id,
                                         volatile)
    if (not current or plugin_name not in current
            or key not in current[plugin_name]):
        if safe:
            return default
        else:
            raise BotException(EXCEPTION, "Key '{}' not found.".format(key))

    if not volatile and location_key not in bot.data_changed:
        bot.data_changed.append(location_key)

    elif key:
        return current[plugin_name].pop(key)
    else:  # Remove all data associated with that plugin for the given location
        return current.pop(plugin_name)
Пример #14
0
def get_text_as_file(bot, text):
    """Converts the text into a bytes object using BytesIO."""
    try:
        # return io.BytesIO(bytes(str(text)), str.encode)
        return io.BytesIO(bytes(str(text), 'utf-8'))
    except Exception as e:
        raise BotException(EXCEPTION, "Failed to convert text to a file.", e=e)
Пример #15
0
def modify_mute_status(bot, change, mute):
    '''
    Mutes or unmutes the given type of to_change (either server or channel).
    '''
    change_id = change.id
    if type(change) is discord.Channel:  # Channel
        change_reference = bot.servers_data[change.server.id]['muted_channels']
        currently_muted = (change.id in change_reference)
        change = 'Channel'
    else:  # Server
        currently_muted = bot.servers_data[change.id]['muted']
        change = 'Server'

    if not (currently_muted ^ mute):
        raise BotException(
            ErrorTypes.RECOVERABLE, EXCEPTION,
            "{} is already {}muted.".format(change, '' if mute else 'un'))
    else:
        if change == 'Channel':
            if mute:
                change_reference.append(change_id)
            else:
                change_reference.remove(change_id)
        else:
            bot.servers_data[change_id]['muted'] = mute
    return change_id
Пример #16
0
def get_mastery_table(bot, static, watcher, name, champion=None):
    '''
    Gets mastery information for the given summoner. If the champion argument
    is specified, it will find the details of that champion only.
    The table generated will be the top 10 champions of the summoner.
    '''
    summoner = get_summoner_wrapper(watcher, name)
    if champion:
        try:
            champion_id = static[1][champion.replace(' ', '').lower()]['id']
            champion_data = get_mastery_wrapper(bot,
                                                summoner['id'],
                                                champion_id=champion_id)
        except KeyError:
            raise BotException(ErrorTypes.RECOVERABLE, EXCEPTION,
                               "Champion not found.")
    else:
        champion_data = get_mastery_wrapper(bot, summoner['id'], top=False)

    labels = '#  | Champion      | Points    | Lvl | Box | Grade | Last Played '
    line = '---|---------------|-----------|-----|-----|-------|-------------'

    if champion:
        labels = labels[5:]
        line = line[5:]

    response = '```\n{}\n{}\n'.format(labels, line)

    if champion:
        response += get_formatted_mastery_data(static, champion_data)
    else:
        for it in range(10):
            response += '{}'.format(it + 1).ljust(3) + '| '
            response += get_formatted_mastery_data(static, champion_data[it])
    return response + '```'
Пример #17
0
def list_data_append(bot,
                     plugin_name,
                     key,
                     value,
                     server_id=None,
                     channel_id=None,
                     user_id=None,
                     volatile=False,
                     duplicates=True):
    """Add data to list at location.

    Works like add, but manipulates the list at the location instead to append
    the given key. It creates the list if it doesn't exist. If the duplicates
    flag is set to false, this will not append the data if it is already found
    inside the list.
    """
    current, location_key = get_location(bot, server_id, channel_id, user_id,
                                         volatile)
    if plugin_name not in current:
        current[plugin_name] = {}
    if key not in current[plugin_name]:  # List doesn't exist
        current[plugin_name][key] = [value]
    else:  # List already exists
        current = current[plugin_name][key]
        if type(current) is not list:
            raise BotException(EXCEPTION, "Data is not a list.")
        elif duplicates or value not in current:
            current.append(value)
        if not volatile and location_key not in bot.data_changed:
            bot.data_changed.append(location_key)
Пример #18
0
async def parallelize(coroutines, return_exceptions=False):
    """Uses asyncio.gather to "parallelize" the coroutines (not really)."""
    try:
        return await asyncio.gather(*coroutines,
                                    return_exceptions=return_exceptions)
    except Exception as e:
        raise BotException(EXCEPTION, "Failed to await coroutines.", e=e)
Пример #19
0
 def check_and_add(dictionary, key, value):
     if key in dictionary:
         raise BotException(
             EXCEPTION,
             "Attempting to add a command that already exists.",
             key,
             error_type=ErrorTypes.FATAL)
     dictionary[key] = value
Пример #20
0
def get_manual(bot, entry, server=None):
    """Gets the given manual entry."""
    invoker = utilities.get_invoker(bot, server=server)
    base_invoker = utilities.get_invoker(bot)
    if entry <= 0:
        raise BotException(EXCEPTION, "Invalid manual entry.")
    for manual in bot.manuals:
        manual_length = len(manual[1]['order'])
        if manual_length >= entry:
            entry_title = manual[1]['order'][entry - 1]
            found_entry = manual[1]['entries'][entry_title]
            response = '***`{0}`*** -- {1}\n\n'.format(manual[0], entry_title)
            return response + found_entry.format(invoker=invoker,
                                                 base_invoker=base_invoker)
        else:
            entry -= manual_length
    raise BotException(EXCEPTION, "Invalid manual entry.")
Пример #21
0
 def convert_and_check(self, bot, message, value):
     if self.convert:
         try:
             if isinstance(value, list):
                 new_values = []
                 for entry in value:
                     new_values.append(self.convert(bot, message, entry))
                 value = new_values
             else:
                 value = self.convert(bot, message, value)
         except Exception as e:
             if hasattr(e, 'error_details'):  # BotException
                 if getattr(self.convert, 'pass_error', False):
                     raise e
                 convert_error = e.error_details
             elif hasattr(self.convert, 'get_convert_error'):
                 convert_error = self.convert.get_convert_error(
                     bot, message, value)
             else:
                 convert_error = self.convert_error
             raise BotException(
                 'Parser',
                 convert_error.format(b=bot, m=message, v=value),
                 embed_fields=self.subcommand.help_embed_fields)
     if self.check:
         try:
             if isinstance(value, list):
                 for entry in value:
                     assert self.check(bot, message, entry)
             else:
                 assert self.check(bot, message, value)
         except Exception as e:
             if hasattr(e, 'error_details'):  # BotException
                 if getattr(self.check, 'pass_error', False):
                     raise e
                 check_error = e.error_details
             elif hasattr(self.check, 'get_check_error'):
                 check_error = self.check.get_check_error(
                     bot, message, value)
             else:
                 check_error = self.check_error
             raise BotException(
                 'Parser',
                 check_error.format(b=bot, m=message, v=value),
                 embed_fields=self.subcommand.help_embed_fields)
     return value
Пример #22
0
async def upload_to_discord(bot, fp, filename=None, rewind=True, close=False):
    """Uploads the given file-like object to the upload channel.

    If the upload channel is specified in the configuration files, files
    will be uploaded there. Otherwise, a new server will be created, and
    used as the upload channel."""
    channel_id = configurations.get(bot, 'core', 'upload_channel')
    if not channel_id:  # Check to see if a server was already created
        channel_id = data.get(bot, 'core', 'upload_channel')
    channel = bot.get_channel(channel_id)

    if channel is None:  # Create server
        logging.debug("Creating server for upload channel...")
        try:
            server = await bot.create_server('uploads')
        except Exception as e:
            raise BotException(
                EXCEPTION,
                "Failed to create upload server. This bot is not whitelisted "
                "to create servers.",
                e=e)
        data.add(bot, 'core', 'upload_channel', server.id)
        channel = bot.get_channel(server.id)

    if channel is None:  # Shouldn't happen
        raise BotException(EXCEPTION, "Failed to get upload channel.")

    try:
        message = await bot.send_file(channel, fp, filename=filename)
        upload_url = message.attachments[0]['url']
    except Exception as e:
        raise BotException(EXCEPTION, "Failed to upload file.", e=e)

    if close:
        try:
            fp.close()
        except:
            pass
    elif rewind:
        try:
            fp.seek(0)
        except:
            pass

    return upload_url
Пример #23
0
def modify_user_group(bot, server, identity, add, which):
    '''
    Add and remove users (either blocked, or moderators) to the servers_data
    dictionary. Throws an error if trying to add and the user is already on the
    list, specified by the which argument.
    '''
    user_id = get_id(bot, identity, server=server)
    which_data = bot.servers_data[server.id][which]
    if add:
        if user_id in which_data:
            raise BotException(ErrorTypes.RECOVERABLE, EXCEPTION,
                               "User already in the {} list.".format(which))
        bot.servers_data[server.id][which].append(user_id)
    else:
        if user_id not in which_data:
            raise BotException(ErrorTypes.RECOVERABLE, EXCEPTION,
                               "User was not in the {} list.".format(which))
        bot.servers_data[server.id][which].remove(user_id)
    return user_id
Пример #24
0
async def add_to_cache(bot, url, name=None, file_location=None):
    """Downloads the URL and saves to the audio cache folder.

    If the cache folder has surpassed the cache size, this will continually
    remove the least used file (by date) until there is enough space. If the
    downloaded file is more than half the size of the total cache, it will not
    be stored. Returns the final location of the downloaded file.

    If name is specified, it will be stored under that name instead of the url.
    If file_location is specified, it will move that file instead of
    downloading the URL.
    """
    if file_location:
        cleaned_name = utilities.get_cleaned_filename(file_location)
    else:
        file_location, cleaned_name = await utilities.download_url(
            bot, url, include_name=True)
    if name:
        cleaned_name = utilities.get_cleaned_filename(name)
    try:
        download_stat = os.stat(file_location)
    except FileNotFoundError:
        raise BotException(
            EXCEPTION, "The audio could not be saved. Please try again later.")
    cache_limit = bot.configurations['core']['cache_size_limit'] * 1000 * 1000
    store = cache_limit > 0 and download_stat.st_size < cache_limit / 2

    if store:
        cached_location = '{0}/audio_cache/{1}'.format(bot.path, cleaned_name)
    else:
        cached_location = '{}/temp/tempsound'.format(bot.path)
    try:
        os.remove(cached_location)
    except:  # Doesn't matter if file doesn't exist
        pass
    os.rename(file_location, cached_location)

    if store:
        cache_entries = []
        total_size = 0
        for entry in os.scandir('{}/audio_cache'.format(bot.path)):
            stat = entry.stat()
            cache_entries.append((stat.st_atime, stat.st_size, entry.path))
            total_size += stat.st_size
        cache_entries.sort(reverse=True)

        # TODO: Check complexity of list entry removal
        while total_size > cache_limit:
            entry = cache_entries.pop()
            os.remove(entry[2])
            total_size -= entry[1]

    return cached_location
Пример #25
0
def get(bot, plugin_name, key=None, extra=None, extension='json'):
    """Gets the configuration file for the given plugin.

    Keyword arguments:
    key -- Gets the specified key from the config file, otherwise everything.
    extra -- Looks for <plugin_name>-<extra>.<extension>
    extension -- If 'json', reads the file as json, otherwise reads it as text.
    """
    if extra:  # Open from external configuration file
        filename = '{0}/config/{1}-{2}.{3}'.format(bot.path, plugin_name,
                                                   extra, extension)
    else:  # Open from configuration dictionary
        try:
            config = bot.configurations[plugin_name]
        except KeyError:
            raise BotException(
                EXCEPTION,
                "Plugin {} not found in the configurations dictionary.".format(
                    plugin_name))
        try:
            if key:
                return config[key]
            else:
                return config
        except KeyError:
            raise BotException(
                EXCEPTION,
                "Key {} not found in the configuration file.".format(key))
    try:
        with open(filename, 'r') as config_file:
            if extension.lower() == 'json':
                return json.load(config_file)
            else:
                return config_file.read()
    except FileNotFoundError:
        raise BotException(EXCEPTION, "File {} not found.".format(filename))
    except Exception as e:
        raise BotException(EXCEPTION,
                           "Failed to read {} properly.".format(filename),
                           e=e)
Пример #26
0
async def execute(bot, message, command, parsed_input, initial_data):
    """Calls get_response of the given plugin associated with the base."""
    if bot.selfbot and command.no_selfbot:
        raise BotException(EXCEPTION,
                           "This command cannot be used in selfbot mode.")

    if not initial_data[3] and command.base in bot.locked_commands:
        raise BotException(EXCEPTION,
                           "This command is locked by the bot owner.")

    if message.channel.is_private:
        if not command.allow_direct:
            raise BotException(EXCEPTION,
                               "Cannot use this command in a direct message.")
        elif 0 < command.elevated_level < 3:
            raise BotException(
                EXCEPTION, "Special permissions commands cannot be used in "
                "direct messages.")
        disabled_commands = []
    else:
        disabled_commands = data.get(bot,
                                     'base',
                                     'disabled',
                                     server_id=message.server.id,
                                     default=[])

    if command.elevated_level > 0:
        if command.elevated_level == 1 and not any(initial_data[1:]):
            raise BotException(EXCEPTION,
                               "Only bot moderators can use this command.")
        elif command.elevated_level == 2 and not any(initial_data[2:]):
            raise BotException(EXCEPTION,
                               "Only the server owner can use this command.")
        elif command.elevated_level >= 3 and not initial_data[3]:
            raise BotException(EXCEPTION,
                               "Only the bot owner(s) can use this command.")

    for disabled_base, disabled_index in disabled_commands:
        if (command.base == disabled_base
                and disabled_index in (-1, parsed_input[1])
                and not any(initial_data[1:])):
            raise BotException(EXCEPTION,
                               "This command is disabled on this server.")

    if command.function:
        given_function = command.function
    else:
        given_function = command.plugin.get_response
    return await (given_function(bot, message, *parsed_input, initial_data[0]))
Пример #27
0
async def download_url(bot, url, include_name=False, extension=None):
    """Asynchronously downloads the given file to the temp folder.

    Returns the path of the downloaded file. If include_name is True, returns
    a tuple of the file location and the file name.
    """
    cleaned_name = get_cleaned_filename(url, extension=extension)
    file_location = '{0}/temp/{1}'.format(bot.path, cleaned_name)
    try:
        response_code, downloaded_bytes = await get_url(
            bot, url, get_bytes=True, headers={'User-Agent': 'Mozilla/5.0'})
        if response_code != 200:
            raise BotException(EXCEPTION, "Failed to download file.",
                               response_code)
        with open(file_location, 'wb') as download:
            download.write(downloaded_bytes)
        if include_name:
            return (file_location, cleaned_name)
        else:
            return file_location
    except Exception as e:
        raise BotException(EXCEPTION, "Failed to download the file.", e=e)
Пример #28
0
def get_help(bot, base, topic=None, is_owner=False, server=None):
    """Gets the help of the base command, or the topic of a help command."""
    try:
        base = base.lower()
        command = bot.commands[base]
    except KeyError:
        raise BotException(
            EXCEPTION, "Invalid command base. Ensure sure you are not "
            "including the command invoker.")

    if command.hidden and not is_owner:
        return '```\nCommand is hidden.```'
    if command.shortcut and base in command.shortcut.bases:
        shortcut_index = command.shortcut.bases.index(base)
        return usage_reminder(bot,
                              base,
                              index=shortcut_index,
                              shortcut=True,
                              is_owner=is_owner,
                              server=server)

    # Handle specific topic help
    if topic is not None:
        try:
            topic_index = int(topic)
        except:  # Guess the help index
            guess = parser.guess_index(bot, '{0} {1}'.format(base, topic))
            topic_index = None if guess[1] == -1 else guess[1] + 1
            return get_help(bot,
                            base,
                            topic=topic_index,
                            is_owner=is_owner,
                            server=server)
        else:  # Proper index given
            return usage_reminder(bot, base, index=topic_index, server=server)

    response = ''
    invoker = utilities.get_invoker(bot, server=server)
    if command.description:
        response += '**Description**:\n{}\n\n'.format(
            command.description.format(invoker=invoker))
    response += usage_reminder(bot, base, is_owner=is_owner,
                               server=server) + '\n'
    if command.shortcut:
        response += usage_reminder(
            bot, base, shortcut=True, is_owner=is_owner, server=server) + '\n'
    if command.other:
        response += '**Other information**:\n{}'.format(
            command.other.format(invoker=invoker))

    return response.rstrip()
Пример #29
0
def get_summoner_wrapper(watcher, name):
    '''
    Wraps the obtaining of a summoner information with exception handling.
    '''
    try:
        summoner = watcher.get_summoner(name=name)
    except LoLException as e:
        if e == error_429:
            api_cooldown()
        else:
            try:  # Maybe we were given an ID
                summoner = watcher.get_summoner(_id=name)
            except Exception as e:
                raise BotException(ErrorTypes.RECOVERABLE,
                                   EXCEPTION,
                                   "Summoner \"" + name + "\" not found.",
                                   e=e)
    except Exception as e:
        raise BotException(ErrorTypes.RECOVERABLE,
                           EXCEPTION,
                           "Failed to retrieve summoner information.",
                           e=e)
    return summoner
Пример #30
0
async def leave_and_stop(bot, server, member=None, safe=True):
    """Leaves any voice channel in the given server and stops any players.

    Keyword arguments:
    member -- Checks that the the bot is connected to the member's
        voice channel. The safe option overrides this.
    safe -- Prevents exceptions from being thrown. Can be seen as 'silent'.
    """
    player = get_player(bot, server.id)
    if player is not None and player.is_playing():
        player.stop()

    voice_client = bot.voice_client_in(server)
    if not voice_client:
        if not safe:
            raise BotException(EXCEPTION,
                               "Bot not connected to a voice channel.")
    elif member and voice_client.channel != member.voice_channel:
        if not safe:
            raise BotException(EXCEPTION,
                               "Bot not connected to your voice channel.")
    else:
        await voice_client.disconnect()