Пример #1
0
import re

from jshbot import commands, logger
from jshbot.commands import ArgTypes
from jshbot.exceptions import ConfiguredBotException

CBException = ConfiguredBotException('Parser')


def split_parameters(parameters, include_quotes=False, quote_list=False):
    """Splits up the given parameters by spaces and quotes.

    Keyword arguments:
    include_quotes -- The quotes attached to the parameters will be included.
    quote_list -- Gets a list of indices that represent parameters that were
        grouped because of quotes.
    """

    if not parameters:
        if quote_list:
            return ([], [])
        else:
            return []
    split = re.split('( +)', parameters)
    quoted_indices = []
    joined_split = []
    add_start = -1
    add_end = -1

    for index, entry in enumerate(split):
        if entry.startswith('"'):
Пример #2
0
import discord
import os
import io
import json
import psycopg2
import psycopg2.extras

from types import GeneratorType

from jshbot import core, utilities, logger
from jshbot.exceptions import BotException, ConfiguredBotException, ErrorTypes

CBException = ConfiguredBotException('Data')


def check_folders(bot):
    """Checks that all of the folders are present at startup."""
    directories = ['audio', 'audio_cache', 'data', 'plugins', 'temp']
    for directory in directories:
        full_path = '{0}/{1}/'.format(bot.path, directory)
        if not os.path.exists(full_path):
            logger.warn("Directory {} does not exist. Creating...".format(directory))
            os.makedirs(full_path)


def check_all(bot):
    """Refreshes the guild listing in the global data dictionary."""
    for guild in bot.guilds:
        guild_id = str(guild.id)
        if guild_id not in bot.data:  # Mirrored with volatile data
            bot.data[guild_id] = {}
Пример #3
0
import asyncio
import gspread 
from google.oauth2.service_account import Credentials 
import datetime
import discord 

from jshbot import data, configurations, plugins, utilities 
from jshbot.exceptions import ConfiguredBotException
from jshbot.commands import (
    Command, SubCommand, ArgTypes, Arg, Opt, Elevation, MessageTypes, Response)

__version__ = '0.2.0'
CBException = ConfiguredBotException('BDO Influence Renewal Plugin')
uses_configuration = True

###################################################################################################
###################################################################################################
### These are specific to a guild anyways, don't need to change the spreadsheet shit. #############
###################################################################################################
###################################################################################################


# SHEET NAMES
SPREADSHEET_NAME = ''
FORM_NAME = ''
MEMBER_LIST_NAME = ''
NW_ATTENDANCE_NAME = ''
NW_SUNDAY = 
NW_MONDAY = 

gc = None
Пример #4
0
import shutil
import yaml
import time
import sys
import os

from logging.handlers import RotatingFileHandler
from concurrent.futures import FIRST_COMPLETED
from collections import namedtuple, OrderedDict
from discord.abc import PrivateChannel

from jshbot import configurations, plugins, commands, parser, data, utilities, base, logger
from jshbot.exceptions import BotException, ConfiguredBotException, ErrorTypes
from jshbot.commands import Response, MessageTypes

CBException = ConfiguredBotException('Core')

exception_insults = [
    'Ow.', 'Ah, shucks.', 'Wow, nice one.', 'That wasn\'t supposed to happen.',
    'Tell Jsh to fix his bot.',
    'I was really hoping that wouldn\'t happen, but it did.',
    'segmentation fault (core dumped)', '0xABADBABE 0xFEE1DEAD',
    ':bomb: Sorry, a system error occurred.', ':bomb: :bomb: :bomb: :bomb:',
    'But... the future refused to be awaited.', 'So... cold...',
    'Yup. Jsh is still awful at Python.', 'Yeah, I was a mistake.',
    'Maybe it won\'t happen next time! *Right...?*', 'Darn.',
    'I... have failed...', 'Well, it was worth a shot.',
    'That one stung a bit.', 'Of *course*. Nothing ever works out, does it?',
    'I yelled at Jsh for you.',
    'Minsoo is bad at osu!. He wanted me to tell you that.',
    'Existence is pain.', 'The Brass is impressed. Good work.',
Пример #5
0
import discord

from jshbot import utilities, data, configurations, plugins, logger
from jshbot.exceptions import BotException, ConfiguredBotException
from jshbot.commands import (
    Command, SubCommand, Shortcut, ArgTypes, Attachment, Arg, Opt, MessageTypes, Response)

__version__ = '0.1.0'
CBException = ConfiguredBotException('0.3 to 0.4 plugin')

@plugins.command_spawner
def get_commands(bot):
    return [Command('convertdata', hidden=True, elevated_level=3)]

async def get_response(bot, context):
    for guild in bot.guilds:
        convert_core(bot, guild)
        if 'tags.py' in bot.plugins:
            convert_tags(bot, guild)
    return Response("Converted.")


def convert_core(bot, guild):
    if data.get(bot, 'core', None, guild_id=guild.id):
        logger.warn("Guild %s (%s) already had core converted", guild.name, guild.id)
        return
    base_data = data.get(bot, 'base', None, guild_id=guild.id, default={})
    if 'disabled' in base_data:
        # TODO: Iterate through toggled commands
        pass
    if 'blocked' in base_data:
Пример #6
0
import discord
import datetime
import time
import json
import codecs

from urllib.parse import urlparse
from psycopg2.extras import Json

from jshbot import data, utilities, configurations, plugins, logger
from jshbot.exceptions import ConfiguredBotException, BotException, ErrorTypes
from jshbot.commands import (
    Command, SubCommand, Shortcut, ArgTypes, Attachment, Arg, Opt, MessageTypes, Response)

__version__ = '0.2.2'
CBException = ConfiguredBotException('Character creator')
uses_configuration = True

DATA_VERSION = 2
DATA_CHANNEL = None
DATA_CHANNEL_WEBHOOK_IDS = []
COMMON_ATTRIBUTES = ['Species', 'Height', 'Age', 'Gender', 'Sexuality']
CHARACTER_TYPES = {
    'fursona': ['A fursona', 'Fursona'],
    'oc': ['An OC', 'OC'],
}


class Character():
    def __init__(self, owner, json_data, tags):
        self.owner = owner
Пример #7
0
import requests
import random
import datetime
import time

from collections import OrderedDict
from bs4 import BeautifulSoup

from jshbot import utilities, data, configurations, plugins, logger
from jshbot.exceptions import BotException, ConfiguredBotException
from jshbot.commands import (Command, SubCommand, Shortcut, ArgTypes,
                             Attachment, Arg, Opt, MessageTypes, Response)

__version__ = '0.2.0'
uses_configuration = True
CBException = ConfiguredBotException('GDQ plugin')


@plugins.command_spawner
def get_commands(bot):
    new_commands = []

    new_commands.append(
        Command(
            'gdq',
            subcommands=[
                SubCommand(doc='Shows the GDQ menu.'),
                SubCommand(Opt('about'),
                           doc='Shows some basic information about GDQ.'),
                SubCommand(
                    Opt('status'),
Пример #8
0
import discord
import random

from jshbot import data, utilities, configurations, logger, plugins
from jshbot.exceptions import BotException, ConfiguredBotException
from jshbot.commands import (Command, SubCommand, Shortcut, ArgTypes, Arg, Opt,
                             MessageTypes, Response)

__version__ = '0.2.0'
CBException = ConfiguredBotException('Simple bot manager')
uses_configuration = False


@plugins.command_spawner
def get_commands(bot):
    new_commands = []

    new_commands.append(
        Command(
            'botman',
            subcommands=[
                SubCommand(
                    Opt('change'),
                    Opt('avatar', optional=True),
                    Opt('status', optional=True),
                    doc=
                    'Changes the avatar, status, or both from the list files.'
                ),
                SubCommand(
                    Opt('nick'),
                    Arg('nickname',
Пример #9
0
import time
import praw
import discord

from prawcore import NotFound
from datetime import datetime

from jshbot import utilities, plugins, configurations, data, logger, parser
from jshbot.exceptions import ConfiguredBotException, BotException
from jshbot.commands import Command, SubCommand, Shortcut, ArgTypes, Arg, Opt, Response

__version__ = '0.1.3'
CBException = ConfiguredBotException('/r/Furry Discord plugin')
CBException_vc = ConfiguredBotException('Verification checker')
uses_configuration = True

REDDIT_CLIENT = None


@plugins.command_spawner
def get_commands(bot):
    return [
        Command(
            'verification',
            subcommands=[
                SubCommand(
                    Opt('check'),
                    Arg('user',
                        argtype=ArgTypes.MERGED_OPTIONAL,
                        quotes_recommended=False,
                        convert=utilities.MemberConverter()),
Пример #10
0
import asyncio
import random
import json
import discord

from jshbot import utilities, configurations, plugins, logger, data
from jshbot.exceptions import BotException, ConfiguredBotException
from jshbot.commands import (
    Command, SubCommand, Shortcut, ArgTypes, Attachment, Arg, Opt, MessageTypes, Response)

__version__ = '0.1.0'
CBException = ConfiguredBotException('Tag remote')
uses_configuration = False

DATA_VERSION = 1
WEBHOOK_SET = set()
TAG_CONVERTER = None

@plugins.command_spawner
def get_commands(bot):
    return [Command(
        'tagremote', subcommands=[
            SubCommand(doc='Gets the current remote session.', function=tagremote),
            SubCommand(
                Opt('start'),
                doc='Starts a sound tag remote session.',
                function=tagremote_start),
            SubCommand(
                Opt('stop'),
                doc='Stops the current sound tag remote session.',
                function=tagremote_stop),
Пример #11
0
import asyncio
import collections
import json
import time
import discord

from datetime import datetime, timezone
from psycopg2.extras import Json

from jshbot import utilities, plugins, configurations, data, logger
from jshbot.exceptions import ConfiguredBotException, BotException
from jshbot.commands import (Command, SubCommand, ArgTypes, Arg, Opt, Response,
                             MessageTypes, Elevation)

__version__ = '0.1.1'
CBException = ConfiguredBotException('Auto chat logger')
uses_configuration = True

DATA_VERSION = 1


@plugins.command_spawner
def get_commands(bot):
    return [
        Command(
            'autolog',
            subcommands=[
                SubCommand(
                    Opt('channels'),
                    Arg('channel',
                        argtype=ArgTypes.SPLIT_OPTIONAL,
Пример #12
0
from jshbot import logger


class ArgTypes(Enum):
    SINGLE, OPTIONAL, SPLIT, SPLIT_OPTIONAL, MERGED, MERGED_OPTIONAL = range(6)


class MessageTypes(Enum):
    NORMAL, PERMANENT, REPLACE, ACTIVE, INTERACTIVE, WAIT = range(6)


from jshbot import parser, utilities, data
from jshbot.exceptions import BotException, ConfiguredBotException, ErrorTypes

CBException = ConfiguredBotException('Commands')


class Response():
    def __init__(self,
                 content=None,
                 tts=False,
                 message_type=MessageTypes.NORMAL,
                 extra=None,
                 embed=None,
                 file=None,
                 files=None,
                 reason=None,
                 delete_after=None,
                 nonce=None,
                 extra_function=None,
Пример #13
0
import asyncio

import xml.etree.ElementTree as ElementTree

from jshbot import utilities, configurations, plugins, logger, data
from jshbot.exceptions import ConfiguredBotException
from jshbot.commands import (
    Command, SubCommand, Shortcut, ArgTypes, Attachment, Arg, Opt, MessageTypes, Response)

__version__ = '0.1.0'
CBException = ConfiguredBotException('Course Checker')
uses_configuration = True
course_url_template = (
    "http://courses.illinois.edu/cisapp/explorer/schedule/{year}/{semester}/"
    "{{department}}{{course_number}}{{crn}}.xml{{detail}}")


# Apply this decorator to every function that returns a list of new commands
@plugins.command_spawner
def get_commands(bot):
    """Returns a list of commands associated with this plugin."""
    new_commands = []

    new_commands.append(Command(
        'crn', subcommands=[
            SubCommand(
                Opt('pending'),
                doc='Lists courses you are waiting on.'),
            SubCommand(
                Opt('watch'),
                Arg('department code'),
Пример #14
0
import random
import io
import discord

import wap

from PIL import Image, ImageDraw, ImageFont
from xml.etree import ElementTree

from jshbot import utilities, data, configurations, plugins, logger
from jshbot.exceptions import ConfiguredBotException
from jshbot.commands import (Command, SubCommand, Shortcut, ArgTypes,
                             Attachment, Arg, Opt, MessageTypes, Response)

__version__ = '0.2.0'
CBException = ConfiguredBotException('Wolfram|Alpha API plugin')
uses_configuration = True


@plugins.command_spawner
def get_commands(bot):
    new_commands = []

    new_commands.append(
        Command(
            'wolfram',
            subcommands=[
                SubCommand(
                    Opt('pro'),
                    doc=
                    'Learn about Wolfram|Alpha Pro and what it can help you accomplish.',
Пример #15
0
import random
import re
import discord

from jshbot import plugins, logger
from jshbot.exceptions import ConfiguredBotException
from jshbot.commands import (Command, SubCommand, Shortcut, ArgTypes,
                             Attachment, Arg, Opt, MessageTypes, Response)

__version__ = '0.2.0'
CBException = ConfiguredBotException('Randomizer')


class RollConverter():
    def __call__(self, bot, message, value, *a):
        value = value.lower().strip().replace(' ', '')
        if not value:
            raise CBException("The specifier cannot be blank.")

        bulk, addition_check, bonus = value.partition('+')
        if bulk and addition_check and not bonus:
            raise CBException(
                "Invalid specifier (must be in *x* d *y* + *z* syntax).")
        if bonus:
            try:
                bonus = int(bonus)
            except:
                raise CBException("Invalid static modifier.")
            if bonus < 1:
                raise CBException("Static modifier must be positive.")
        else:
Пример #16
0
import discord

from jshbot import utilities, plugins, data, logger
from jshbot.exceptions import ConfiguredBotException
from jshbot.commands import Command, SubCommand, ArgTypes, Arg, Opt, Response

__version__ = '0.1.2'
CBException = ConfiguredBotException('Role assigner')
uses_configuration = False


@plugins.command_spawner
def get_commands(bot):
    return [Command(
        'role', subcommands=[
            SubCommand(
                Opt('join'),
                Arg('role name', argtype=ArgTypes.SPLIT, convert=utilities.RoleConverter()),
                doc='Join a role (or multiple).',
                function=role_joinleave, id='join'),
            SubCommand(
                Opt('leave'),
                Arg('role name', argtype=ArgTypes.SPLIT, convert=utilities.RoleConverter()),
                doc='Leave a role (or multiple).',
                function=role_joinleave, id='leave'),
            SubCommand(
                Opt('toggle'),
                Arg('role name', argtype=ArgTypes.SPLIT, convert=utilities.RoleConverter()),
                doc='Toggle self-assignable roles.',
                elevated_level=1, function=role_toggle),
            SubCommand(
Пример #17
0
import json
import yaml

from jshbot.exceptions import ConfiguredBotException, ErrorTypes

CBException = ConfiguredBotException('Configurations')


def get(bot, plugin_name, key=None, extra=None, extension='yaml'):
    """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[:-3],
                                                   extra, extension)
    else:  # Open from configuration dictionary
        try:
            config = bot.configurations[plugin_name]
        except KeyError:
            raise CBException(
                "Plugin {} not found in the configurations dictionary.".format(
                    plugin_name))
        try:
            if key:
                return config[key]
            else:
                return config
Пример #18
0
import discord
import asyncio
import aiohttp
import functools
import shutil
import socket
import datetime
import json
import time
import os
import io

from jshbot import data, configurations, core, logger
from jshbot.exceptions import BotException, ConfiguredBotException

CBException = ConfiguredBotException('Utilities')

# Voice region time offsets (no DST)
voice_regions = {
    'us-west': -8,
    'us-east': -5,
    'us-south': -6,
    'us-central': -6,
    'eu-west': 1,  # West European Summer Time
    'eu-central': 2,  # Central European Summer Time
    'singapore': 8,
    'london': 0,
    'sydney': 10,
    'amsterdam': 2,  # CEST
    'frankfurt': 2,  # CEST
    'brazil': -3,
Пример #19
0
import json
import datetime

import discord

from jshbot import utilities, configurations, plugins, logger
from jshbot.exceptions import ConfiguredBotException
from jshbot.commands import Command, Response

__version__ = '0.1.0'
CBException = ConfiguredBotException('Emoji updater')
uses_configuration = True


@plugins.command_spawner
def get_commands(bot):
    return [Command('ude', elevated_level=3, hidden=True)]


async def get_response(bot, context):
    if 'discrank.py' not in bot.plugins:
        raise CBException("Discrank plugin not detected.")
    discrank_plugin = bot.plugins['discrank.py']
    champions, spells = discrank_plugin.CHAMPIONS, discrank_plugin.SPELLS

    chunks = [
        bot.get_guild(it).emojis
        for it in configurations.get(bot, __name__, 'guilds')
    ]
    emojis = [it for chunk in chunks for it in chunk]
Пример #20
0
import time
import random
import unicodedata
import re

import discord

from jshbot import utilities, configurations, plugins, data, logger
from jshbot.exceptions import ConfiguredBotException
from jshbot.commands import (Command, SubCommand, Shortcut, ArgTypes,
                             Attachment, Arg, Opt, MessageTypes, Response)

__version__ = '0.1.4'
CBException = ConfiguredBotException('Awoo police')
uses_configuration = True

statements = None
substitutions = None
fine = None
BASIC_MATCH = re.compile(r'\ba+w+oo+\b')
ADVANCED_MATCH = re.compile(r'\ba+[a\s]*w+[w\s]*o\s*o+(\b|[\sise])')
PLEA_MATCH = re.compile(r'legali[zs]e *a+w+oo+')


@plugins.command_spawner
def get_commands(bot):
    return [
        Command(
            'awoo',
            subcommands=[
                SubCommand(doc='Get fined.', allow_direct=False,
Пример #21
0
import io
import json
import discord

from PIL import Image, ImageDraw, ImageFilter, ImageOps

from jshbot import utilities, plugins, configurations, data, logger, parser
from jshbot.exceptions import ConfiguredBotException, BotException
from jshbot.commands import (Command, SubCommand, Shortcut, ArgTypes, Arg, Opt,
                             Response, Attachment, MessageTypes)

__version__ = '0.1.1'
CBException = ConfiguredBotException('Pride flag creator')
uses_configuration = False

PRIDE_FLAGS = None


class FlagConverter():
    def __init__(self,
                 include_flag_list=True,
                 allow_urls=True,
                 check_attachments=False):
        self.include_flag_list = include_flag_list
        self.allow_urls = allow_urls
        self.check_attachments = check_attachments

    def __call__(self, bot, message, value, *a):
        cleaned = utilities.clean_text(value, level=4).replace('flag',
                                                               '').replace(
                                                                   'pride', '')
Пример #22
0
#
# Lastly, there is a small amount of demo code to show off that plugins can
#   define standard events from discord.Client, and they will be called
#   appropriately.
#
###############################################################################

import asyncio

from jshbot import utilities, configurations, plugins, logger
from jshbot.exceptions import ConfiguredBotException
from jshbot.commands import (Command, SubCommand, Shortcut, ArgTypes,
                             Attachment, Arg, Opt, MessageTypes, Response)

__version__ = '0.2.0'
CBException = ConfiguredBotException('Dummy')
uses_configuration = True


# Apply this decorator to every function that returns a list of new commands
@plugins.command_spawner
def get_commands(bot):
    """Returns a list of commands associated with this plugin."""
    new_commands = []

    new_commands.append(
        Command(
            'mycommand',
            subcommands=[
                SubCommand(
                    Opt('myoption'),
Пример #23
0
import googletrans
import discord

from jshbot import utilities, plugins, configurations, data, logger
from jshbot.exceptions import ConfiguredBotException
from jshbot.commands import Command, SubCommand, Shortcut, ArgTypes, Arg, Opt, Response

__version__ = '0.1.0'
CBException = ConfiguredBotException('Translator')
uses_configuration = False
TRANSLATOR = googletrans.Translator()
LANGUAGE_LINK = (
    '[Click here for a list of supported languages.]'
    '(https://en.wikipedia.org/wiki/Google_Translate#Supported_languages)')


@plugins.command_spawner
def get_commands(bot):
    return [Command(
        'translate', subcommands=[
            SubCommand(
                Opt('default'),
                Arg('language', argtype=ArgTypes.MERGED_OPTIONAL),
                doc='Sets the default translation language. (Default is `en`)',
                elevated_level=1, function=translate_default),
            SubCommand(
                Opt('languages'),
                doc='Gets a list of valid language codes.',
                function=translate_languages),
            SubCommand(
                Opt('from', attached='language', optional=True),
Пример #24
0
import discord
import time
from enum import IntEnum

from jshbot import utilities, data, plugins, logger
from jshbot.exceptions import ConfiguredBotException
from jshbot.commands import (Command, SubCommand, Shortcut, ArgTypes,
                             Attachment, Arg, Opt, MessageTypes, Response)


class TextTypes(IntEnum):
    THOUGHT, FOOTER = range(2)


__version__ = '0.1.2'
CBException = ConfiguredBotException('txyz plugin')
uses_configuration = False

UPDATE_HOURS = 24
MAIN_BOT = 179181152777535488
TXYZ_GUILD = 371885514049191937
DEFAULTS = ["Looks like my head is a bit empty right now.", "💔︎"]
TYPE_NAMES = ['thoughts', 'footers']


class TXYZTypeConverter():
    def __call__(self, bot, message, value, *a):
        value = value.lower().strip()
        identity = {'thought': TextTypes.THOUGHT, 'footer': TextTypes.FOOTER}
        if value not in identity:
            raise CBException("Must be either `thought` or `footer`.")
Пример #25
0
import discord
from youtube_dl import YoutubeDL

from jshbot import utilities, configurations, plugins, data, logger
from jshbot.exceptions import ConfiguredBotException, BotException
from jshbot.commands import (Command, SubCommand, Shortcut, ArgTypes,
                             Attachment, Arg, Opt, MessageTypes, Response)

__version__ = '0.1.0'
CBException = ConfiguredBotException('Play test')
uses_configuration = False


@plugins.command_spawner
def get_commands(bot):
    return [Command('playtest', subcommands=[SubCommand(Arg('url'))])]


async def get_response(bot, context):
    response = Response()
    if context.author.voice:
        voice_channel = context.author.voice.channel
        voice_client = await utilities.join_and_ready(bot, voice_channel)

        options = {'format': 'bestaudio/best', 'noplaylist': True}
        downloader = YoutubeDL(options)
        url = context.arguments[0]
        try:
            file_location = data.get_from_cache(bot, None, url=url)
            if not file_location:
                logger.info("Not found in cache. Downloading...")
Пример #26
0
import time
import random
import math
import urllib
import json
import io
import discord

from jshbot.utilities import future
from jshbot import data, utilities, configurations, logger, plugins, parser
from jshbot.exceptions import BotException, ConfiguredBotException, ErrorTypes
from jshbot.commands import (
    Command, SubCommand, Shortcut, ArgTypes, Attachment, Arg, Opt, MessageTypes, Response)
    
__version__ = '0.1.0'
CBException = ConfiguredBotException('BDO Find Plugin')
uses_configuration = True


def get_commands(bot):
    new_commands = []
    
    new_commands.append(Command(
        'find', subcommands=[
            SubCommand(
                Opt('start'),
                Arg('character_name'),
                Arg('bell'),
                doc='Initalizes the search for a given user.',
                function=to_be_named),
            SubCommand(
Пример #27
0
import time
import discord

from datetime import timezone as tz

from jshbot import utilities, plugins, configurations, data, logger
from jshbot.exceptions import ConfiguredBotException
from jshbot.commands import Command, SubCommand, Shortcut, ArgTypes, Arg, Opt, Response

__version__ = '0.1.1'
CBException = ConfiguredBotException('Commission channel checker')
uses_configuration = True


@plugins.command_spawner
def get_commands(bot):
    return [
        Command(
            'commission',
            subcommands=[
                SubCommand(Opt('configure'),
                           Opt('channel',
                               attached='channel name',
                               optional=True,
                               convert=utilities.ChannelConverter(
                                   constraint=discord.TextChannel,
                                   attribute='id')),
                           Opt('cooldown',
                               attached='seconds',
                               optional=True,
                               convert=int,
Пример #28
0
import asyncio
import copy
import yaml
import importlib.util
import os.path
import sys

# Debug
import traceback

from collections import OrderedDict

from jshbot import commands, utilities, data, logger
from jshbot.exceptions import ErrorTypes, BotException, ConfiguredBotException

CBException = ConfiguredBotException('Plugins')
command_spawner_functions = []
db_template_functions = []
command_load_functions = []

numeric_words = [
    ':zero:', ':one:', ':two:', ':three:', ':four:', ':five:', ':six:',
    ':seven:', ':eight:', ':nine:', ':ten:'
]


def command_spawner(function):
    command_spawner_functions.append(function)
    return function