<commit_before>from datetime import datetime
import asyncio

from discord.ext import commands
import discord
import pydest

from cogs.utils.message_manager import MessageManager
from cogs.utils import constants

class Destiny:

    def __init__(self, bot):
        self.bot = bot

    @commands.command()
    @commands.cooldown(rate=2, per=5, type=commands.BucketType.user)
    async def nightfall(self, ctx):
        """Display the weekly nightfall info"""
        manager = MessageManager(ctx)
        await ctx.channel.trigger_typing()

        try:
            weekly = await self.bot.destiny.api.get_public_milestones()
        except pydest.PydestException as e:
            await manager.send_message("Sorry, I can't seem retrieve the nightfall info right now")
            return await manager.clean_messages()

        if weekly['ErrorCode'] != 1:
            await manager.send_message("Sorry, I can't seem retrieve the nightfall info right now")
            return await manager.clean_messages()

        nightfall_hash = weekly['Response']['2171429505']['availableQuests'][0]['activity']['activityHash']
        nightfall = await self.bot.destiny.decode_hash(nightfall_hash, 'DestinyActivityDefinition')

        challenges = ""
        for entry in nightfall['challenges']:
            challenge = await self.bot.destiny.decode_hash(entry['objectiveHash'], 'DestinyObjectiveDefinition')
            challenge_name = challenge['displayProperties']['name']
            challenge_description = challenge['displayProperties']['description']
            challenges += "**{}** - {}\n".format(challenge_name, challenge_description)

        modifiers = ""
        for entry in weekly['Response']['2171429505']['availableQuests'][0]['activity']['modifierHashes']:
            modifier = await self.bot.destiny.decode_hash(entry, 'DestinyActivityModifierDefinition')
            modifier_name = modifier['displayProperties']['name']
            modifier_description = modifier['displayProperties']['description']
            modifiers += "**{}** - {}\n".format(modifier_name, modifier_description)

        e = discord.Embed(title='{}'.format(nightfall['displayProperties']['name']), colour=constants.BLUE)
        e.description = "*{}*".format(nightfall['displayProperties']['description'])
        e.set_thumbnail(url=('https://www.bungie.net' + nightfall['displayProperties']['icon']))
        e.add_field(name='Challenges', value=challenges)
        e.add_field(name='Modifiers', value=modifiers)

        await manager.send_embed(e)
        await manager.clean_messages()
<commit_msg>Temporarily remove nightfall modifiers<commit_after>from datetime import datetime
import asyncio

from discord.ext import commands
import discord
import pydest

from cogs.utils.message_manager import MessageManager
from cogs.utils import constants

class Destiny:

    def __init__(self, bot):
        self.bot = bot

    @commands.command()
    @commands.cooldown(rate=2, per=5, type=commands.BucketType.user)
    async def nightfall(self, ctx):
        """Display the weekly nightfall info"""
        manager = MessageManager(ctx)
        await ctx.channel.trigger_typing()

        try:
            weekly = await self.bot.destiny.api.get_public_milestones()
        except pydest.PydestException as e:
            await manager.send_message("Sorry, I can't seem retrieve the nightfall info right now")
            return await manager.clean_messages()

        if weekly['ErrorCode'] != 1:
            await manager.send_message("Sorry, I can't seem retrieve the nightfall info right now")
            return await manager.clean_messages()

        nightfall_hash = weekly['Response']['2171429505']['availableQuests'][0]['activity']['activityHash']
        nightfall = await self.bot.destiny.decode_hash(nightfall_hash, 'DestinyActivityDefinition')

        challenges = ""
        for entry in nightfall['challenges']:
            challenge = await self.bot.destiny.decode_hash(entry['objectiveHash'], 'DestinyObjectiveDefinition')
            challenge_name = challenge['displayProperties']['name']
            challenge_description = challenge['displayProperties']['description']
            challenges += "**{}** - {}\n".format(challenge_name, challenge_description)

        e = discord.Embed(title='{}'.format(nightfall['displayProperties']['name']), colour=constants.BLUE)
        e.description = "*{}*".format(nightfall['displayProperties']['description'])
        e.set_thumbnail(url=('https://www.bungie.net' + nightfall['displayProperties']['icon']))
        e.add_field(name='Challenges', value=challenges)

        await manager.send_embed(e)
        await manager.clean_messages()
<|endoftext|>


<commit_before>import discord

from discord.ext import commands
from utils.checks import is_staff

class Filter(commands.Cog):
    """
    Commands to manage the filter.
    """
    def __init__(self, bot):
        self.bot = bot

    # Command group for the word filter
    @is_staff("Helper")
    @commands.group()
    async def wordfilter(self, ctx):
        if ctx.invoked_subcommand is None:
            await ctx.send_help(ctx.command)

    @is_staff("SuperOP")
    @wordfilter.command(name='add')
    async def add_word(self, ctx, word: str, *, kind: str):
        if kind not in self.bot.wordfilter.kinds:
            return await ctx.send(f"Possible word kinds for word filter: {', '.join(self.bot.wordfilter.kinds)}")
        if ' ' in word or '-' in word:
            return await ctx.send("Filtered words cant contain dashes or spaces!")
        entry = await self.bot.wordfilter.add(word=word, kind=kind)
        if word is None:
            return await ctx.send(f"Failed to add word to {kind} filter")
        await self.bot.channels['mod-logs'].send(f"🆕 **Added**: {ctx.author.mention} added `{entry.word}` to the word filter!")
        await ctx.send("Successfully added word to word filter")

    @wordfilter.command(name='list')
    async def list_words(self, ctx):
        embed = discord.Embed()
        for kind in self.bot.wordfilter.kinds:
            if self.bot.wordfilter.filter[kind]:
                embed.add_field(name=kind, value='\n'.join(self.bot.wordfilter.filter[kind]))
        if embed:
            await ctx.author.send(embed=embed)
        else:
            await ctx.send("The word filter is empty!")

    @is_staff("SuperOP")
    @wordfilter.command(name='delete', aliases=['remove'])
    async def delete_word(self, ctx, word: str):
        entry = await self.bot.wordfilter.delete(word=word)
        if entry is None:
            return await ctx.send("Word not found!")
        await ctx.send(f"Delete word `{word}` succesfully!")
        await self.bot.channels['mod-logs'].send(f"⭕ **Deleted**: {ctx.author.mention} deleted word `{entry.word}` from the filter!")

    @is_staff("Helper")
    @commands.group()
    async def invitefilter(self, ctx):
        """Command group for managing the invite filter"""
        if ctx.invoked_subcommand is None:
            await ctx.send_help(ctx.command)

    @is_staff("SuperOP")
    @invitefilter.command(name='add')
    async def add_invite(self, ctx, invite: discord.Invite, alias: str):
        """Adds a invite to the filter whitelist"""
        if await self.bot.invitefilter.fetch_invite_by_alias(alias) or await self.bot.invitefilter.fetch_invite_by_code(invite.code):
            return await ctx.send("This invite code or alias is already in use!")
        entry = await self.bot.invitefilter.add(code=invite.code, alias=alias, uses=-1)
        if entry is None:
            return await ctx.send("Failed to add invite to the invite whitelist!")
        await self.bot.channels['mod-logs'].send(f"🆕 **Added**: {ctx.author.mention} added {invite.code}(`{invite.guild.name}`) to the invite whitelist!")
        await ctx.send("Successfully added invite to whitelist")

    @is_staff("SuperOP")
    @invitefilter.command(name='delete')
    async def delete_invite(self, ctx, code: str):
        """Removes a invite from the filter whitelist"""
        entry = await self.bot.invitefilter.fetch_invite_by_code(code=code)
        if not entry:
            return await ctx.send("Invite code not found!")
        await self.bot.invitefilter.delete(code=code)
        await ctx.send(f"Deleted server `{entry.alias}` from filter succesfully!")
        await self.bot.channels['mod-logs'].send(f"⭕ **Deleted**: {ctx.author.mention} deleted server `{entry.alias}` from the invite filter!")

    @invitefilter.command(name='list')
    async def list_invites(self, ctx):
        """List invites in the filter whitelist"""
        embed = discord.Embed()
        if self.bot.invitefilter.invites:
            embed.add_field(name='Invites', value='\n'.join(f"name: {invite.alias} code:{invite.code} uses:{invite.uses}" for invite in self.bot.invitefilter.invites))
            await ctx.send(embed=embed)
        else:
            await ctx.send("The invite filter is empty!")

def setup(bot):
    bot.add_cog(Filter(bot))
<commit_msg>filters.py: delete_word can now delete multiple words at the same time<commit_after>import discord

from discord.ext import commands
from utils.checks import is_staff

class Filter(commands.Cog):
    """
    Commands to manage the filter.
    """
    def __init__(self, bot):
        self.bot = bot

    # Command group for the word filter
    @is_staff("Helper")
    @commands.group()
    async def wordfilter(self, ctx):
        if ctx.invoked_subcommand is None:
            await ctx.send_help(ctx.command)

    @is_staff("SuperOP")
    @wordfilter.command(name='add')
    async def add_word(self, ctx, word: str, *, kind: str):
        if kind not in self.bot.wordfilter.kinds:
            return await ctx.send(f"Possible word kinds for word filter: {', '.join(self.bot.wordfilter.kinds)}")
        if ' ' in word or '-' in word:
            return await ctx.send("Filtered words cant contain dashes or spaces!")
        entry = await self.bot.wordfilter.add(word=word, kind=kind)
        if word is None:
            return await ctx.send(f"Failed to add word to {kind} filter")
        await self.bot.channels['mod-logs'].send(f"🆕 **Added**: {ctx.author.mention} added `{entry.word}` to the word filter!")
        await ctx.send("Successfully added word to word filter")

    @wordfilter.command(name='list')
    async def list_words(self, ctx):
        embed = discord.Embed()
        for kind in self.bot.wordfilter.kinds:
            if self.bot.wordfilter.filter[kind]:
                embed.add_field(name=kind, value='\n'.join(self.bot.wordfilter.filter[kind]))
        if embed:
            await ctx.author.send(embed=embed)
        else:
            await ctx.send("The word filter is empty!")

    @is_staff("SuperOP")
    @wordfilter.command(name='delete', aliases=['remove'])
    async def delete_word(self, ctx, *, words: str):
        words = words.split()
        deleted = []
        for word in words:
            entry = await self.bot.wordfilter.delete(word=word)
            if entry:
                deleted.append(entry.word)
        if deleted:
            await ctx.send(f"Deleted words `{'`,`'.join(deleted)}` succesfully!")
            await self.bot.channels['mod-logs'].send(f"⭕ **Deleted**: {ctx.author.mention} deleted words `{'`,`'.join(deleted)}` from the filter!")
        else:
            await ctx.send("No word was deleted from the filter!")

    @is_staff("Helper")
    @commands.group()
    async def invitefilter(self, ctx):
        """Command group for managing the invite filter"""
        if ctx.invoked_subcommand is None:
            await ctx.send_help(ctx.command)

    @is_staff("SuperOP")
    @invitefilter.command(name='add')
    async def add_invite(self, ctx, invite: discord.Invite, alias: str):
        """Adds a invite to the filter whitelist"""
        if await self.bot.invitefilter.fetch_invite_by_alias(alias) or await self.bot.invitefilter.fetch_invite_by_code(invite.code):
            return await ctx.send("This invite code or alias is already in use!")
        entry = await self.bot.invitefilter.add(code=invite.code, alias=alias, uses=-1)
        if entry is None:
            return await ctx.send("Failed to add invite to the invite whitelist!")
        await self.bot.channels['mod-logs'].send(f"🆕 **Added**: {ctx.author.mention} added {invite.code}(`{invite.guild.name}`) to the invite whitelist!")
        await ctx.send("Successfully added invite to whitelist")

    @is_staff("SuperOP")
    @invitefilter.command(name='delete')
    async def delete_invite(self, ctx, code: str):
        """Removes a invite from the filter whitelist"""
        entry = await self.bot.invitefilter.fetch_invite_by_code(code=code)
        if not entry:
            return await ctx.send("Invite code not found!")
        await self.bot.invitefilter.delete(code=code)
        await ctx.send(f"Deleted server `{entry.alias}` from filter succesfully!")
        await self.bot.channels['mod-logs'].send(f"⭕ **Deleted**: {ctx.author.mention} deleted server `{entry.alias}` from the invite filter!")

    @invitefilter.command(name='list')
    async def list_invites(self, ctx):
        """List invites in the filter whitelist"""
        embed = discord.Embed()
        if self.bot.invitefilter.invites:
            embed.add_field(name='Invites', value='\n'.join(f"name: {invite.alias} code:{invite.code} uses:{invite.uses}" for invite in self.bot.invitefilter.invites))
            await ctx.send(embed=embed)
        else:
            await ctx.send("The invite filter is empty!")

def setup(bot):
    bot.add_cog(Filter(bot))
<|endoftext|>


<commit_before>from decimal import *
import time
import datetime
import traceback
import locale
import discord
from discord.ext import commands
from dateutil import parser
import colour

class Finance:
    def __init__(self, bot):
        self.bot = bot
        self.legal_notice = "Data is not guaranteed to be accurate, "\
                            "I am not responsible for your losses."

    def get_change_color(self, change_percentage, color_range: int = 10):
        """Gets a change color between red-white-green for the given change percentage"""
        change_percentage = str(change_percentage).split('.')[0]  # before the dot
        red = colour.Color("#D50000")
        white = colour.Color("#FFFFFF")
        green = colour.Color("#1B5E20")

        int_perc = int(change_percentage)

        if int_perc is 0:
            return self.bot.hex_to_int("#ffffff")
        elif change_percentage.startswith('-'):
            colors = list(red.range_to(white, color_range))
            int_perc = int_perc * -1  # make it positive
            int_perc = color_range - int_perc
            int_perc = int_perc if int_perc > 0 else 0 # limit
            return self.bot.hex_to_int(colors[int_perc].hex_l)
        else:
            int_perc -= 1
            colors = list(white.range_to(green, color_range))
            int_perc = int_perc if int_perc < (color_range - 1) else (color_range - 1) # limit
            return self.bot.hex_to_int(colors[int_perc].hex_l)

    def format_currency(self, amount, locale_to_use: str = "en_US.UTF-8"):
        """Formats a currency for the given locale (default: en_US.UTF-8)"""
        try:
            locale.setlocale(locale.LC_ALL, locale_to_use)
            amount = Decimal(amount)
            return locale.currency(amount, grouping=True)
        except:
            self.bot.log.error(f"Error while converting {amount} on "
                               f"format_currency: {traceback.format_exc()}")

    async def get_stock_change_color(self, ticker: str):
        symbols = await self.bot.aiojson("https://api.robinhood.com/quotes/"\
                                        f"?symbols={ticker.upper()}")
        if not symbols:
            return 0x000000 # black

        symbols_results = symbols["results"][0]

        current_price = (symbols_results["last_trade_price"] if
                         "last_extended_hours_trade_price" in symbols_results
                         else symbols_results["last_extended_hours_trade_price"])

        diff = str(Decimal(current_price) -
                   Decimal(symbols_results["previous_close"]))
        percentage = (100 * Decimal(diff) / Decimal(current_price))
        return self.get_change_color(percentage, 10)

    async def get_crypto_name(self, ticker: str, include_ticker=True):
        """Fetches the name of the given cryptocurrency from Cryptopia API"""
        ticker = ticker.upper()
        json_data = await self.bot.aiojson("https://www.cryptopia.co.nz/api/GetCurrencies")
        if not ("Success" in json_data and json_data["Success"]):
            return ticker if include_ticker else None
        name_list = [data["Name"]
                     for data in json_data["Data"] if data["Symbol"] == ticker]
        if not name_list:
            return ticker if include_ticker else None
        return f"{name_list[0]} ({ticker})" if include_ticker else name_list[0]

    async def get_conversion_rate(self, from_symbol: str, to_symbol: str):
        json_res = await self.bot.aiojson("https://api.fixer.io/latest"\
                                          f"?base={from_symbol.upper()}"\
                                          f"&symbols={to_symbol.upper()}")
        if "rates" in json_res and json_res["rates"]:
            return json_res["rates"][to_symbol.upper()]
        return None

    @commands.command(aliases=['stockchart', 'c'])
    async def chart(self, ctx, ticker: str):
        """Returns stock chart of the given ticker.

        Usage example: ab!c seb"""
        image_link = f"https://finviz.com/chart.ashx?t={ticker.upper()}"\
                     f"&ty=c&ta=1&p=d&s=l&cacheinval={int(time.time())}"
        title_link = f"https://finviz.com/quote.ashx?t={ticker.upper()}"
        change_color = await self.get_stock_change_color(ticker)
        embed = discord.Embed(title=f'Chart for {ticker.upper()}',
                              colour=change_color,
                              url=title_link)
        embed.set_image(url=image_link)
        embed.set_footer(text='Powered by finviz.com')
        await ctx.send(embed=embed)

    # TODO: Find a way to reduce code repetition in following messages
    @commands.command(aliases=['howmuch', 'convert', 'conversion', 'conversionrate'])
    async def currency(self, ctx, from_symbol: str, to_symbol: str):
        """Gives the conversion rate for given symbols.

        Usage example: ab!currency BRL TRY"""
        rate = await self.get_conversion_rate(from_symbol, to_symbol)
        if rate:
            await ctx.send(f"{ctx.author.mention}: "\
                           f"1{from_symbol.upper()} = {rate}{to_symbol.upper()}."\
                           "\n(Powered by fixer.io, data is refreshed daily. "\
                           f"{self.legal_notice})")
        else:
            await ctx.send("One of the symbols is not recognized.")

    @commands.command(aliases=['currencyconvert', 'currencyconversion'])
    async def money(self, ctx, amount, from_symbol: str, to_symbol: str):
        """Gives a currency conversion for given amount of money.

        Usage example: ab!money 100 BRL TRY"""
        rate = await self.get_conversion_rate(from_symbol, to_symbol)
        if rate:
            result_amount = Decimal(rate) * Decimal(amount)
            result_amount = round(result_amount, 2)
            await ctx.send(f"{ctx.author.mention}: "\
                           f"{amount}{from_symbol.upper()} = {result_amount}{to_symbol.upper()}."\
                           "\n(Powered by fixer.io, data is renewed daily. "\
                           f"{self.legal_notice})")
        else:
            await ctx.send("One of the symbols is not recognized.")

    @commands.command(aliases=['s'])
    async def stock(self, ctx, ticker: str):
        """Returns stock info about the given ticker.

        Usage example: ab!s seb"""
        symbols = await self.bot.aiojson("https://api.robinhood.com/quotes/"\
                                        f"?symbols={ticker.upper()}")
        if not symbols:
            await ctx.send("Stock not found. This stock is probably not tradeable on robinhood.")
            return
        symbols_result = symbols["results"][0]
        instrument = await self.bot.aiojson(symbols_result["instrument"])
        fundamentals = await self.bot.aiojson(
            f"https://api.robinhood.com/fundamentals/{ticker.upper()}/")

        current_price = (symbols_result["last_trade_price"] if
                         "last_extended_hours_trade_price" in symbols_result
                         else symbols_result["last_extended_hours_trade_price"])
        diff = Decimal(Decimal(current_price) -
                       Decimal(symbols_result["previous_close"]))
        percentage = str(100 * diff / current_price)[:6]

        if not percentage.startswith("-"):
            percentage = "+" + percentage

        current_price_string = self.format_currency(current_price)
        diff_string = self.format_currency(diff)
        bid_price_string = self.format_currency(Decimal(symbols_result["bid_price"]))
        ask_price_string = self.format_currency(Decimal(symbols_result["ask_price"]))
        tradeable_string = (
            ":white_check_mark:" if instrument["tradeable"] else ":x:")

        update_timestamp = parser.parse(symbols_result["updated_at"])

        symbol = symbols_result["symbol"]
        change_color = await self.get_stock_change_color(symbol)

        embed = discord.Embed(title=f"{symbol}'s stocks info",
                              color=change_color,
                              timestamp=update_timestamp)

        embed.add_field(name="Name", value=instrument["name"])
        embed.add_field(name="Current Price", value=current_price_string)
        embed.add_field(name="Change from yesterday", value=f"{diff_string} ({percentage}%)")
        embed.add_field(name="Bid size", value=f"{symbols_result['bid_size']} ({bid_price_string})")
        embed.add_field(name="Ask size", value=f"{symbols_result['ask_size']} ({ask_price_string})")
        embed.add_field(name="Current Volume", value=fundamentals["volume"])
        embed.add_field(name="Average Volume", value=fundamentals["average_volume"])
        embed.add_field(name="Tradeable on Robinhood", value=tradeable_string)
        embed.add_field(name="Country", value=f":flag_{instrument['country'].lower()}:")

        await ctx.send(embed=embed)

    @commands.command()
    async def btc(self, ctx):
        """Returns 30 day bitcoin chart and price info."""
        try:
            btc_bitstamp_json = await self.bot.aiojson("https://www.bitstamp.net/api/ticker")

            btc_currentprice_rate = Decimal(btc_bitstamp_json["last"])
            btc_currentprice_string = self.format_currency(btc_currentprice_rate)

            btc_lastopen_rate = Decimal(btc_bitstamp_json["open"])
            btc_lastopen_string = self.format_currency(btc_lastopen_rate)

            btc_high_string = self.format_currency(btc_bitstamp_json["high"])
            btc_low_string = self.format_currency(btc_bitstamp_json["low"])
            btc_bid_string = self.format_currency(btc_bitstamp_json["bid"])
            btc_ask_string = self.format_currency(btc_bitstamp_json["ask"])
            btc_volume_string = str(btc_bitstamp_json["volume"]) + " BTC"

            btc_diff = btc_currentprice_rate - btc_lastopen_rate
            btc_change_percentage = (
                100 * Decimal(btc_diff) / Decimal(btc_currentprice_rate))
            btc_change_percentage_string = f"{str(btc_change_percentage)[:6]}%"

            btc_change_color = self.get_change_color(btc_change_percentage, 20)

            btc_data_timestamp = datetime.datetime.utcfromtimestamp(
                int(btc_bitstamp_json["timestamp"]))

            link = "https://bitcoincharts.com/charts/chart.png?width=600&m=bitstampUSD&r=30"\
                  f"&t=S&v=1&cacheinval={int(time.time())}"
            embed = discord.Embed(color=btc_change_color,
                                  timestamp=btc_data_timestamp)

            embed.set_author(name="30 Day BTC Chart and Info",
                             icon_url="https://bitcoin.org/img/icons/opengraph.png")
            embed.set_image(url=link)
            embed.set_footer(text="Chart supplied by bitcoincharts.com under CC-BY-SA 3.0, "\
                                  "price info supplied by BitStamp. " + self.legal_notice)

            embed.add_field(name="Current Price", value=btc_currentprice_string)
            embed.add_field(name="Opening Price", value=btc_lastopen_string)

            embed.add_field(name="Change", value=btc_change_percentage_string)
            embed.add_field(name="Volume", value=btc_volume_string)

            embed.add_field(name="High", value=btc_high_string)
            embed.add_field(name="Low", value=btc_low_string)

            embed.add_field(name="Bid", value=btc_bid_string)
            embed.add_field(name="Ask", value=btc_ask_string)

            await ctx.send(embed=embed)
        except:
            await ctx.send("Error while fetching BTC data.")
            self.bot.log.error(traceback.format_exc())

    @commands.command(aliases=["cryptocoin", "cryptoprice", "cc"])
    async def crypto(self, ctx, ticker: str):
        """Returns price info about the specified cryptocoin."""
        ticker = ticker.upper()
        api_endpoint = "https://min-api.cryptocompare.com/data/pricemultifull"\
                       f"?tsyms=USD&fsyms={ticker}"
        api_json = await self.bot.aiojson(api_endpoint)
        if "Message" in api_json:
            await ctx.send(f"Error from API: `{api_json['Message']}`")
            return

        raw_data = api_json["RAW"][ticker]["USD"]
        stylized_data = api_json["DISPLAY"][ticker]["USD"]

        change_color = self.get_change_color(raw_data["CHANGEPCTDAY"], 20)

        data_timestamp = datetime.datetime.utcfromtimestamp(
            raw_data["LASTUPDATE"])

        coin_name = await self.get_crypto_name(ticker)

        embed = discord.Embed(color=change_color, timestamp=data_timestamp)

        embed.set_author(name=f"Price info for {coin_name} from {stylized_data['MARKET']}")
        embed.set_footer(text="Price info supplied by CryptoCompare. " + self.legal_notice)

        embed.add_field(name="Current Price", value=stylized_data["PRICE"])
        embed.add_field(name="Opening Price", value=stylized_data["OPENDAY"])

        embed.add_field(name="Change", value=f"{stylized_data['CHANGEDAY']} "\
                                             f"({stylized_data['CHANGEPCTDAY']}%)")
        embed.add_field(name="Volume", value=stylized_data["VOLUMEDAY"])

        embed.add_field(name="High", value=stylized_data["HIGHDAY"])
        embed.add_field(name="Low", value=stylized_data["LOWDAY"])

        await ctx.send(embed=embed)

def setup(bot):
    bot.add_cog(Finance(bot))
<commit_msg>finance: change color ranges<commit_after>from decimal import *
import time
import datetime
import traceback
import locale
import discord
from discord.ext import commands
from dateutil import parser
import colour

class Finance:
    def __init__(self, bot):
        self.bot = bot
        self.legal_notice = "Data is not guaranteed to be accurate, "\
                            "I am not responsible for your losses."

    def get_change_color(self, change_percentage, color_range: int = 5):
        """Gets a change color between red-white-green for the given change percentage"""
        change_percentage = str(change_percentage).split('.')[0]  # before the dot
        red = colour.Color("#D50000")
        white = colour.Color("#FFFFFF")
        green = colour.Color("#1B5E20")

        int_perc = int(change_percentage)

        if int_perc is 0:
            return self.bot.hex_to_int("#ffffff")
        elif change_percentage.startswith('-'):
            colors = list(red.range_to(white, color_range))
            int_perc = int_perc * -1  # make it positive
            int_perc = color_range - int_perc
            int_perc = int_perc if int_perc > 0 else 0 # limit
            return self.bot.hex_to_int(colors[int_perc].hex_l)

        int_perc -= 1
        colors = list(white.range_to(green, color_range))
        int_perc = int_perc if int_perc < (color_range - 1) else (color_range - 1) # limit
        return self.bot.hex_to_int(colors[int_perc].hex_l)

    def format_currency(self, amount, locale_to_use: str = "en_US.UTF-8"):
        """Formats a currency for the given locale (default: en_US.UTF-8)"""
        try:
            locale.setlocale(locale.LC_ALL, locale_to_use)
            amount = Decimal(amount)
            return locale.currency(amount, grouping=True)
        except:
            self.bot.log.error(f"Error while converting {amount} on "
                               f"format_currency: {traceback.format_exc()}")

    async def get_stock_change_color(self, ticker: str):
        symbols = await self.bot.aiojson("https://api.robinhood.com/quotes/"\
                                        f"?symbols={ticker.upper()}")
        if not symbols:
            return 0x000000 # black

        symbols_results = symbols["results"][0]

        current_price = (symbols_results["last_trade_price"] if
                         "last_extended_hours_trade_price" in symbols_results
                         else symbols_results["last_extended_hours_trade_price"])

        diff = str(Decimal(current_price) -
                   Decimal(symbols_results["previous_close"]))
        percentage = (100 * Decimal(diff) / Decimal(current_price))
        return self.get_change_color(percentage, 5)

    async def get_crypto_name(self, ticker: str, include_ticker=True):
        """Fetches the name of the given cryptocurrency from Cryptopia API"""
        ticker = ticker.upper()
        json_data = await self.bot.aiojson("https://www.cryptopia.co.nz/api/GetCurrencies")
        if not ("Success" in json_data and json_data["Success"]):
            return ticker if include_ticker else None
        name_list = [data["Name"]
                     for data in json_data["Data"] if data["Symbol"] == ticker]
        if not name_list:
            return ticker if include_ticker else None
        return f"{name_list[0]} ({ticker})" if include_ticker else name_list[0]

    async def get_conversion_rate(self, from_symbol: str, to_symbol: str):
        json_res = await self.bot.aiojson("https://api.fixer.io/latest"\
                                          f"?base={from_symbol.upper()}"\
                                          f"&symbols={to_symbol.upper()}")
        if "rates" in json_res and json_res["rates"]:
            return json_res["rates"][to_symbol.upper()]
        return None

    @commands.command(aliases=['stockchart', 'c'])
    async def chart(self, ctx, ticker: str):
        """Returns stock chart of the given ticker.

        Usage example: ab!c seb"""
        image_link = f"https://finviz.com/chart.ashx?t={ticker.upper()}"\
                     f"&ty=c&ta=1&p=d&s=l&cacheinval={int(time.time())}"
        title_link = f"https://finviz.com/quote.ashx?t={ticker.upper()}"
        change_color = await self.get_stock_change_color(ticker)
        embed = discord.Embed(title=f'Chart for {ticker.upper()}',
                              colour=change_color,
                              url=title_link)
        embed.set_image(url=image_link)
        embed.set_footer(text='Powered by finviz.com')
        await ctx.send(embed=embed)

    # TODO: Find a way to reduce code repetition in following messages
    @commands.command(aliases=['howmuch', 'convert', 'conversion', 'conversionrate'])
    async def currency(self, ctx, from_symbol: str, to_symbol: str):
        """Gives the conversion rate for given symbols.

        Usage example: ab!currency BRL TRY"""
        rate = await self.get_conversion_rate(from_symbol, to_symbol)
        if rate:
            await ctx.send(f"{ctx.author.mention}: "\
                           f"1{from_symbol.upper()} = {rate}{to_symbol.upper()}."\
                           "\n(Powered by fixer.io, data is refreshed daily. "\
                           f"{self.legal_notice})")
        else:
            await ctx.send("One of the symbols is not recognized.")

    @commands.command(aliases=['currencyconvert', 'currencyconversion'])
    async def money(self, ctx, amount, from_symbol: str, to_symbol: str):
        """Gives a currency conversion for given amount of money.

        Usage example: ab!money 100 BRL TRY"""
        rate = await self.get_conversion_rate(from_symbol, to_symbol)
        if rate:
            result_amount = Decimal(rate) * Decimal(amount)
            result_amount = round(result_amount, 2)
            await ctx.send(f"{ctx.author.mention}: "\
                           f"{amount}{from_symbol.upper()} = {result_amount}{to_symbol.upper()}."\
                           "\n(Powered by fixer.io, data is renewed daily. "\
                           f"{self.legal_notice})")
        else:
            await ctx.send("One of the symbols is not recognized.")

    @commands.command(aliases=['s'])
    async def stock(self, ctx, ticker: str):
        """Returns stock info about the given ticker.

        Usage example: ab!s seb"""
        symbols = await self.bot.aiojson("https://api.robinhood.com/quotes/"\
                                        f"?symbols={ticker.upper()}")
        if not symbols:
            await ctx.send("Stock not found. This stock is probably not tradeable on robinhood.")
            return
        symbols_result = symbols["results"][0]
        instrument = await self.bot.aiojson(symbols_result["instrument"])
        fundamentals = await self.bot.aiojson(
            f"https://api.robinhood.com/fundamentals/{ticker.upper()}/")

        current_price = (symbols_result["last_trade_price"] if
                         "last_extended_hours_trade_price" in symbols_result
                         else symbols_result["last_extended_hours_trade_price"])
        diff = Decimal(Decimal(current_price) -
                       Decimal(symbols_result["previous_close"]))
        percentage = str(100 * diff / current_price)[:6]

        if not percentage.startswith("-"):
            percentage = "+" + percentage

        current_price_string = self.format_currency(current_price)
        diff_string = self.format_currency(diff)
        bid_price_string = self.format_currency(Decimal(symbols_result["bid_price"]))
        ask_price_string = self.format_currency(Decimal(symbols_result["ask_price"]))
        tradeable_string = (
            ":white_check_mark:" if instrument["tradeable"] else ":x:")

        update_timestamp = parser.parse(symbols_result["updated_at"])

        symbol = symbols_result["symbol"]
        change_color = await self.get_stock_change_color(symbol)

        embed = discord.Embed(title=f"{symbol}'s stocks info",
                              color=change_color,
                              timestamp=update_timestamp)

        embed.add_field(name="Name", value=instrument["name"])
        embed.add_field(name="Current Price", value=current_price_string)
        embed.add_field(name="Change from yesterday", value=f"{diff_string} ({percentage}%)")
        embed.add_field(name="Bid size", value=f"{symbols_result['bid_size']} ({bid_price_string})")
        embed.add_field(name="Ask size", value=f"{symbols_result['ask_size']} ({ask_price_string})")
        embed.add_field(name="Current Volume", value=fundamentals["volume"])
        embed.add_field(name="Average Volume", value=fundamentals["average_volume"])
        embed.add_field(name="Tradeable on Robinhood", value=tradeable_string)
        embed.add_field(name="Country", value=f":flag_{instrument['country'].lower()}:")

        await ctx.send(embed=embed)

    @commands.command()
    async def btc(self, ctx):
        """Returns 30 day bitcoin chart and price info."""
        try:
            btc_bitstamp_json = await self.bot.aiojson("https://www.bitstamp.net/api/ticker")

            btc_currentprice_rate = Decimal(btc_bitstamp_json["last"])
            btc_currentprice_string = self.format_currency(btc_currentprice_rate)

            btc_lastopen_rate = Decimal(btc_bitstamp_json["open"])
            btc_lastopen_string = self.format_currency(btc_lastopen_rate)

            btc_high_string = self.format_currency(btc_bitstamp_json["high"])
            btc_low_string = self.format_currency(btc_bitstamp_json["low"])
            btc_bid_string = self.format_currency(btc_bitstamp_json["bid"])
            btc_ask_string = self.format_currency(btc_bitstamp_json["ask"])
            btc_volume_string = str(btc_bitstamp_json["volume"]) + " BTC"

            btc_diff = btc_currentprice_rate - btc_lastopen_rate
            btc_change_percentage = (
                100 * Decimal(btc_diff) / Decimal(btc_currentprice_rate))
            btc_change_percentage_string = f"{str(btc_change_percentage)[:6]}%"

            btc_change_color = self.get_change_color(btc_change_percentage, 10)

            btc_data_timestamp = datetime.datetime.utcfromtimestamp(
                int(btc_bitstamp_json["timestamp"]))

            link = "https://bitcoincharts.com/charts/chart.png?width=600&m=bitstampUSD&r=30"\
                  f"&t=S&v=1&cacheinval={int(time.time())}"
            embed = discord.Embed(color=btc_change_color,
                                  timestamp=btc_data_timestamp)

            embed.set_author(name="30 Day BTC Chart and Info",
                             icon_url="https://bitcoin.org/img/icons/opengraph.png")
            embed.set_image(url=link)
            embed.set_footer(text="Chart supplied by bitcoincharts.com under CC-BY-SA 3.0, "\
                                  "price info supplied by BitStamp. " + self.legal_notice)

            embed.add_field(name="Current Price", value=btc_currentprice_string)
            embed.add_field(name="Opening Price", value=btc_lastopen_string)

            embed.add_field(name="Change", value=btc_change_percentage_string)
            embed.add_field(name="Volume", value=btc_volume_string)

            embed.add_field(name="High", value=btc_high_string)
            embed.add_field(name="Low", value=btc_low_string)

            embed.add_field(name="Bid", value=btc_bid_string)
            embed.add_field(name="Ask", value=btc_ask_string)

            await ctx.send(embed=embed)
        except:
            await ctx.send("Error while fetching BTC data.")
            self.bot.log.error(traceback.format_exc())

    @commands.command(aliases=["cryptocoin", "cryptoprice", "cc"])
    async def crypto(self, ctx, ticker: str):
        """Returns price info about the specified cryptocoin."""
        ticker = ticker.upper()
        api_endpoint = "https://min-api.cryptocompare.com/data/pricemultifull"\
                       f"?tsyms=USD&fsyms={ticker}"
        api_json = await self.bot.aiojson(api_endpoint)
        if "Message" in api_json:
            await ctx.send(f"Error from API: `{api_json['Message']}`")
            return

        raw_data = api_json["RAW"][ticker]["USD"]
        stylized_data = api_json["DISPLAY"][ticker]["USD"]

        change_color = self.get_change_color(raw_data["CHANGEPCTDAY"], 10)

        data_timestamp = datetime.datetime.utcfromtimestamp(
            raw_data["LASTUPDATE"])

        coin_name = await self.get_crypto_name(ticker)

        embed = discord.Embed(color=change_color, timestamp=data_timestamp)

        embed.set_author(name=f"Price info for {coin_name} from {stylized_data['MARKET']}")
        embed.set_footer(text="Price info supplied by CryptoCompare. " + self.legal_notice)

        embed.add_field(name="Current Price", value=stylized_data["PRICE"])
        embed.add_field(name="Opening Price", value=stylized_data["OPENDAY"])

        embed.add_field(name="Change", value=f"{stylized_data['CHANGEDAY']} "\
                                             f"({stylized_data['CHANGEPCTDAY']}%)")
        embed.add_field(name="Volume", value=stylized_data["VOLUMEDAY"])

        embed.add_field(name="High", value=stylized_data["HIGHDAY"])
        embed.add_field(name="Low", value=stylized_data["LOWDAY"])

        await ctx.send(embed=embed)

def setup(bot):
    bot.add_cog(Finance(bot))
<|endoftext|>


<commit_before>import random
import re
from datetime import datetime

import discord
from discord.ext import commands
from discord.utils import escape_mentions

class Generic(commands.Cog):
    DICE_PATTERN = re.compile("\d+d\d+")

    def __init__(self, bot):
        self.bot = bot
        self.blue = discord.Color.dark_blue()

    @commands.command(name="decide")
    async def _decide(self, ctx: commands.Context, *, to_decide: str):
        """Decide between a list of comma separated options"""
        options = [x.strip() for x in to_decide.split(",")]
        choice = random.choice(options)

        await ctx.send(escape_mentions(choice))

    @commands.command(name="await", hidden=True)
    async def _await(self, ctx: commands.Context):
        reactions = ["🅰", "🇼", "🇦", "🇮", "🇹"]
        for reaction in reactions:
            await ctx.message.add_reaction(reaction)

    @commands.command(name="roll", aliases=["dice"])
    async def _roll(self, ctx: commands.Context, *, dice: str):
        """Roll some dice
        Format: XdY - where 1 <= X <= 10 and 1 <= Y <= 100
        Example: qt.roll 3d6"""
        if not self.DICE_PATTERN.match(dice.lower()):
            return await ctx.error(
                "Roll must be in the format XdY",
                description="where 1 <= X <= 10 and 1 <= Y <= 100",
            )
        else:
            match = self.DICE_PATTERN.match(dice.lower()).group()

        num, sides = [int(x) for x in match.split("d")]
        if num < 1 or num > 10 or sides < 1 or sides > 100:
            return await ctx.error(
                "Roll must be in the format XdY",
                description="where 1 <= X <= 10 and 1 <= Y <= 100",
            )

        rolls = [random.choice(range(1, sides + 1)) for x in range(num)]

        em = discord.Embed(color=discord.Color.blurple())
        em.set_author(
            name=f"{ctx.author.display_name} rolled {num}d{sides}",
            icon_url=ctx.author.avatar_url,
        )
        em.add_field(name=":game_die: Rolls", value=", ".join([str(x) for x in rolls]))
        em.add_field(name=":game_die: Total", value=str(sum(rolls)), inline=False)

        await ctx.send(embed=em)

    @commands.command(hidden=True)
    async def say(self, ctx: commands.Context, *, message):
        """ Make qtbot say anything ;) """
        await ctx.message.delete()
        await ctx.send(message)

    @commands.command(name="8ball", aliases=["ball"])
    async def ball(self, ctx: commands.Context, *, query=None):
        """ Ask the magic 8ball """
        if query is None:
            return await ctx.error("The 8Ball's wisdom is not to be wasted.")

        responses = [
            "It is certain",
            "It is decidedly so",
            "Without a doubt",
            "Yes definitely",
            "You may rely on it",
            "As I see it, yes",
            "Most likely",
            "Outlook good",
            "Yes",
            "Signs point to yes",
            "Reply hazy try again",
            "Ask again later",
            "Better not tell you now",
            "Cannot predict now",
            "Concentrate and ask again",
            "Don't count on it",
            "My reply is no",
            "My sources say no",
            "Outlook not so good",
            "Very doubtful",
        ]

        if not query.endswith("?"):
            query = f"{query}?"

        await ctx.send(
            embed=discord.Embed(
                title=f":8ball: {query}",
                description=random.choice(responses),
                color=self.blue,
            )
        )

    @commands.command()
    async def same(self, ctx):
        await ctx.send("```[✓] same\n[ ] unsame```")

    @commands.command()
    async def unsame(self, ctx):
        await ctx.send("```[ ] same\n[✓] unsame```")

    @commands.command()
    async def resame(self, ctx):
        await ctx.send("```[✓] same\n[✓] re:same\n[ ] unsame```")

    @commands.command()
    async def slap(self, ctx: commands.Context, *, target=None):
        """ Teach someone a lesson """
        if target is None:
            return await ctx.send(
                f"{ctx.author.name} thrusts his hands wildly about in the air."
            )

        await ctx.send(
            f"{ctx.author.name} slaps {target} around a bit with a large trout."
        )

    @commands.command()
    async def report(self, ctx):
        """ Report a user """
        await ctx.success(
            f"Thank you for your report. This incident has been sent to the proper authorities. "
            "We'll take it from here."
        )

    @commands.command()
    async def love(self, ctx: commands.Context, *, target=None):
        """ Give someone some lovin' """

        if not target:
            return await ctx.send(f"{ctx.author.display_name} loves ... nothing")

        await ctx.send(
            f":heart_decoration: {ctx.author.display_name} gives {target} some good ol' fashioned lovin'. :heart_decoration:"
        )

    @commands.command(aliases=["at"])
    async def aesthetify(self, ctx: commands.Context, *, a_text):
        """ Make your message ａｅｓｔｈｅｔｉｃ，　ｍａｎ """
        ascii_to_wide = dict((i, chr(i + 0xFEE0)) for i in range(0x21, 0x7F))
        ascii_to_wide.update({0x20: "\u3000", 0x2D: "\u2212"})

        await ctx.message.delete()
        await ctx.send(f"{a_text.translate(ascii_to_wide)}")

    @commands.command(aliases=["up"])
    async def uptime(self, ctx):
        """Get current bot uptime."""
        current_time = datetime.now()
        em = discord.Embed(title=":clock1: Qtbot Uptime", color=self.blue)
        em.add_field(name="Initialized", value=self.bot.start_time_str, inline=False)
        em.add_field(
            name="Uptime", value=str(current_time - self.bot.start_time).split(".")[0]
        )

        await ctx.send(embed=em)

    @commands.command(aliases=["pong"])
    async def ping(self, ctx):
        """See the bot's latency"""
        latency = ctx.bot.latency * 1000
        em = discord.Embed(
            title=":ping_pong: Pong!",
            description=f"**Bot latency:** ```{latency:.2f} ms```",
            color=self.blue,
        )

        await ctx.send(embed=em)

    @commands.command()
    async def about(self, ctx):
        """Get information about qtbot"""
        em = discord.Embed(
            title=":information_source: About qtbot",
            description="Qtbot is a general purpose bot with a load of functionality. Call the help"
            " command via `qt.help` to receive a message with a full list of commands.",
            color=self.blue,
        )
        em.add_field(name="Total Servers", value=f"`{len(self.bot.guilds):,}`")
        em.add_field(name="Total Users", value=f"`{len(self.bot.users):,}`")
        em.add_field(name="Total Commands", value=f"`{len(self.bot.commands)}`")
        em.add_field(
            name="Disclaimer",
            value="Qtbot does not collect messages or information on any users unless "
            "that user specifically opts to share it via a command. Information "
            "that may be willingly shared includes:\n"
            "\u2022 `Location (for weather & forecast)`\n"
            "\u2022 `League of Legends username`\n"
            "\u2022 `Oldschool Runescape username`\n"
            "\u2022 `A link to an Oldschool Runescape screenshot`\n"
            "If you have any questions about this contact the owner below.",
        )
        em.add_field(name="Owner", value="`naught0#4417`")

        await ctx.send(embed=em)

def setup(bot):
    bot.add_cog(Generic(bot))
<commit_msg>send choice in an embed<commit_after>import random
import re
from datetime import datetime

import discord
from discord.ext import commands

class Generic(commands.Cog):
    DICE_PATTERN = re.compile("\d+d\d+")

    def __init__(self, bot):
        self.bot = bot
        self.blue = discord.Color.dark_blue()

    @commands.command(name="decide")
    async def _decide(self, ctx: commands.Context, *, to_decide: str):
        """Decide between a list of comma separated options"""
        options = [x.strip() for x in to_decide.split(",")]
        choice = random.choice(options)

        await ctx.send(
            embed=discord.Embed(color=discord.Color.blurple(), description=choice)
        )

    @commands.command(name="await", hidden=True)
    async def _await(self, ctx: commands.Context):
        reactions = ["🅰", "🇼", "🇦", "🇮", "🇹"]
        for reaction in reactions:
            await ctx.message.add_reaction(reaction)

    @commands.command(name="roll", aliases=["dice"])
    async def _roll(self, ctx: commands.Context, *, dice: str):
        """Roll some dice
        Format: XdY - where 1 <= X <= 10 and 1 <= Y <= 100
        Example: qt.roll 3d6"""
        if not self.DICE_PATTERN.match(dice.lower()):
            return await ctx.error(
                "Roll must be in the format XdY",
                description="where 1 <= X <= 10 and 1 <= Y <= 100",
            )
        else:
            match = self.DICE_PATTERN.match(dice.lower()).group()

        num, sides = [int(x) for x in match.split("d")]
        if num < 1 or num > 10 or sides < 1 or sides > 100:
            return await ctx.error(
                "Roll must be in the format XdY",
                description="where 1 <= X <= 10 and 1 <= Y <= 100",
            )

        rolls = [random.choice(range(1, sides + 1)) for x in range(num)]

        em = discord.Embed(color=discord.Color.blurple())
        em.set_author(
            name=f"{ctx.author.display_name} rolled {num}d{sides}",
            icon_url=ctx.author.avatar_url,
        )
        em.add_field(name=":game_die: Rolls", value=", ".join([str(x) for x in rolls]))
        em.add_field(name=":game_die: Total", value=str(sum(rolls)), inline=False)

        await ctx.send(embed=em)

    @commands.command(hidden=True)
    async def say(self, ctx: commands.Context, *, message):
        """ Make qtbot say anything ;) """
        await ctx.message.delete()
        await ctx.send(message)

    @commands.command(name="8ball", aliases=["ball"])
    async def ball(self, ctx: commands.Context, *, query=None):
        """ Ask the magic 8ball """
        if query is None:
            return await ctx.error("The 8Ball's wisdom is not to be wasted.")

        responses = [
            "It is certain",
            "It is decidedly so",
            "Without a doubt",
            "Yes definitely",
            "You may rely on it",
            "As I see it, yes",
            "Most likely",
            "Outlook good",
            "Yes",
            "Signs point to yes",
            "Reply hazy try again",
            "Ask again later",
            "Better not tell you now",
            "Cannot predict now",
            "Concentrate and ask again",
            "Don't count on it",
            "My reply is no",
            "My sources say no",
            "Outlook not so good",
            "Very doubtful",
        ]

        if not query.endswith("?"):
            query = f"{query}?"

        await ctx.send(
            embed=discord.Embed(
                title=f":8ball: {query}",
                description=random.choice(responses),
                color=self.blue,
            )
        )

    @commands.command()
    async def same(self, ctx):
        await ctx.send("```[✓] same\n[ ] unsame```")

    @commands.command()
    async def unsame(self, ctx):
        await ctx.send("```[ ] same\n[✓] unsame```")

    @commands.command()
    async def resame(self, ctx):
        await ctx.send("```[✓] same\n[✓] re:same\n[ ] unsame```")

    @commands.command()
    async def slap(self, ctx: commands.Context, *, target=None):
        """ Teach someone a lesson """
        if target is None:
            return await ctx.send(
                f"{ctx.author.name} thrusts his hands wildly about in the air."
            )

        await ctx.send(
            f"{ctx.author.name} slaps {target} around a bit with a large trout."
        )

    @commands.command()
    async def report(self, ctx):
        """ Report a user """
        await ctx.success(
            f"Thank you for your report. This incident has been sent to the proper authorities. "
            "We'll take it from here."
        )

    @commands.command()
    async def love(self, ctx: commands.Context, *, target=None):
        """ Give someone some lovin' """

        if not target:
            return await ctx.send(f"{ctx.author.display_name} loves ... nothing")

        await ctx.send(
            f":heart_decoration: {ctx.author.display_name} gives {target} some good ol' fashioned lovin'. :heart_decoration:"
        )

    @commands.command(aliases=["at"])
    async def aesthetify(self, ctx: commands.Context, *, a_text):
        """ Make your message ａｅｓｔｈｅｔｉｃ，　ｍａｎ """
        ascii_to_wide = dict((i, chr(i + 0xFEE0)) for i in range(0x21, 0x7F))
        ascii_to_wide.update({0x20: "\u3000", 0x2D: "\u2212"})

        await ctx.message.delete()
        await ctx.send(f"{a_text.translate(ascii_to_wide)}")

    @commands.command(aliases=["up"])
    async def uptime(self, ctx):
        """Get current bot uptime."""
        current_time = datetime.now()
        em = discord.Embed(title=":clock1: Qtbot Uptime", color=self.blue)
        em.add_field(name="Initialized", value=self.bot.start_time_str, inline=False)
        em.add_field(
            name="Uptime", value=str(current_time - self.bot.start_time).split(".")[0]
        )

        await ctx.send(embed=em)

    @commands.command(aliases=["pong"])
    async def ping(self, ctx):
        """See the bot's latency"""
        latency = ctx.bot.latency * 1000
        em = discord.Embed(
            title=":ping_pong: Pong!",
            description=f"**Bot latency:** ```{latency:.2f} ms```",
            color=self.blue,
        )

        await ctx.send(embed=em)

    @commands.command()
    async def about(self, ctx):
        """Get information about qtbot"""
        em = discord.Embed(
            title=":information_source: About qtbot",
            description="Qtbot is a general purpose bot with a load of functionality. Call the help"
            " command via `qt.help` to receive a message with a full list of commands.",
            color=self.blue,
        )
        em.add_field(name="Total Servers", value=f"`{len(self.bot.guilds):,}`")
        em.add_field(name="Total Users", value=f"`{len(self.bot.users):,}`")
        em.add_field(name="Total Commands", value=f"`{len(self.bot.commands)}`")
        em.add_field(
            name="Disclaimer",
            value="Qtbot does not collect messages or information on any users unless "
            "that user specifically opts to share it via a command. Information "
            "that may be willingly shared includes:\n"
            "\u2022 `Location (for weather & forecast)`\n"
            "\u2022 `League of Legends username`\n"
            "\u2022 `Oldschool Runescape username`\n"
            "\u2022 `A link to an Oldschool Runescape screenshot`\n"
            "If you have any questions about this contact the owner below.",
        )
        em.add_field(name="Owner", value="`naught0#4417`")

        await ctx.send(embed=em)

def setup(bot):
    bot.add_cog(Generic(bot))
<|endoftext|>


<commit_before>from io import BytesIO
import re

import aiohttp
from lxml import etree
import yaml

from discord.ext import commands
from discord import File

from utils.contextmanagers import get as _get

class Twitter:
    """Contains the capability to link images from tweets and other social media"""
    twit_url_expr = re.compile(r'https?://(?:www\.)?twitter\.com/\S+/status/\d+')
    tweet_selector = ".//div[contains(@class, 'tweet permalink-tweet')]"
    twit_img_selector = './/img[@data-aria-label-part]'

    pixiv_url_expr = re.compile(r'https?://(?:www\.)?pixiv\.net/member_illust\.php\??(?:&?[^=&]*=[^=&>\s]*)*')
    pixiv_img_selector = ".//img[@class='original-image']"
    pixiv_read_more_selector = ".//a[contains(@class, 'read-more')]"
    pixiv_manga_page_selector = ".//div[contains(@class, 'item-container')]/a"

    hiccears_url_expr = re.compile(r'https?://(?:www\.)?hiccears\.com/(?:(?:gallery)|(?:picture))\.php\?[gp]id=\d+')
    hiccears_link_selector = ".//div[contains(@class, 'row')]//a"
    hiccears_img_selector = ".//a[contains(@href, 'imgs')]"

    tumblr_url_expr = re.compile(r'https?://[\w-]+\.tumblr\.com/post/\d+')
    tumblr_img_selector = ".//meta[@property='og:image']"

    def __init__(self, bot):
        self.bot = bot
        self.bot.loop.create_task(self.__init())
        self.headers = {'User-Agent':
                        'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) '
                        'Gecko/20100101 Firefox/58.0'}
        with open('config/cookies.yaml') as fp:
            cookies = yaml.load(fp)
        self.session = aiohttp.ClientSession(loop=bot.loop, cookies=cookies)
        self.parser = etree.HTMLParser()

    async def __init(self):
        await self.bot.wait_until_ready()
        if not self.bot.user.bot:
            self.bot.unload_extension(__name__)

    def __unload(self):
        self.session.close()

    def get(self, *args, **kwargs):
        kwargs['headers'] = {**self.headers, **kwargs.get('headers', {})}
        return _get(self.session, *args, **kwargs)

    async def on_message(self, message):
        guild = message.guild
        if guild is None:
            return
        if message.author == guild.me:
            return
        if not (await self.bot.config.get(guild.id)).get('twitter'):
            return
        for link in self.twit_url_expr.findall(message.content):
            await self.display_twitter_images(link, message.channel)
        for link in self.pixiv_url_expr.findall(message.content):
            await self.display_pixiv_images(link, message.channel)
        for link in self.hiccears_url_expr.findall(message.content):
            await self.display_hiccears_images(link, message.channel)
        for link in self.tumblr_url_expr.findall(message.content):
            await self.display_tumblr_images(link, message.channel)

    async def display_twitter_images(self, link, destination):
        async with self.get(link) as resp:
            root = etree.fromstring(await resp.read(), self.parser)
        try:
            tweet = root.xpath(self.tweet_selector)[0]
        except IndexError:
            return
        for img_link in tweet.findall(self.twit_img_selector)[1:]:
            url = img_link.get('src')
            await destination.send(f'{url}:orig')

    async def display_pixiv_images(self, link, destination):
        if 'mode' in link:
            link = re.sub('(?<=mode=)\w+', 'medium', link)
        else:
            link = f'{link}&mode=medium'
        link = link.replace('http://', 'https://')
        async with self.get(link) as resp:
            root = etree.fromstring(await resp.read(), self.parser)
        is_manga = root.xpath(self.pixiv_read_more_selector)
        if is_manga:
            manga_url = link.replace('medium', 'manga')
            heads = {'referer': manga_url}
            heads.update(self.headers)
            async with self.get(manga_url) as resp:
                root = etree.fromstring(await resp.read(), self.parser)
            pages = root.xpath(self.pixiv_manga_page_selector)
            for page in pages[:4]:
                href = page.get('href')
                fullsize_url = f'https://{resp.host}{href}'
                async with self.get(fullsize_url, headers=heads) as page_resp:
                    page_root = etree.fromstring(await page_resp.read(), self.parser)
                page_heads = heads.copy()
                page_heads['referer'] = fullsize_url
                img_url = page_root.find('.//img').get('src')
                filename = img_url.rpartition('/')[2]
                img = BytesIO()
                async with self.get(img_url, headers=heads) as img_resp:
                    async for chunk in img_resp.content.iter_any():
                        if chunk:
                            img.write(chunk)
                img.seek(0)
                file = File(img, filename)
                await destination.send(file=file)
            num = len(pages) - 4
            if num > 0:
                s = 's' if num > 1 else ''
                message = f'{num} more image{s} at <{manga_url}>'
                await destination.send(message)
        else:
            heads = {'referer': link}
            heads.update(self.headers)
            img_elem = root.xpath(self.pixiv_img_selector)
            if img_elem:
                await destination.send('single image')
                img_elem = img_elem[0]
                url = img_elem.get('data-src')
                filename = url.rpartition('/')[2]
                img_request = self.get(url, headers=heads)
                async with img_request as resp:
                    content = await resp.read()
                img = BytesIO()
                img.write(content)
                img.seek(0)
                file = File(img, filename)
                await destination.send(file=file)
            else:
                msg = await destination.send('Fetching gif...')
                params = {
                    'url': link,
                    'format': 'gif',
                    }
                conv_url = 'http://ugoira.dataprocessingclub.org/convert'
                async with self.get(conv_url, params=params) as resp:
                    text = await resp.text()
                url = re.findall('(http.*\.gif)', text)[0]
                img = BytesIO()
                async with self.get(url) as resp:
                    async for block in resp.content.iter_any():
                        if not block:
                            break
                        img.write(block)
                img.seek(0)
                name = url.rpartition('/')[2]
                file = File(img, name)
                await destination.send(file=file)
                await msg.delete()

    async def display_hiccears_images(self, link, destination):
        async with self.get(link) as resp:
            root = etree.fromstring(await resp.read(), self.parser)
        single_image = root.xpath(self.hiccears_img_selector)
        if single_image:
            a = single_image[0]
            href = a.get('href').lstrip('.')
            url = f'https://{resp.host}{href}'
            await destination.send(url)
            return

        images = root.xpath(self.hiccears_link_selector)
        for image in images[:4]:
            href = image.get('href')
            url = f'https://{resp.host}{href[1:]}'
            async with self.get(url) as page_resp:
                page = etree.fromstring(await page_resp.read(), self.parser)
            a = page.xpath(self.hiccears_img_selector)[0]
            href = a.get('href')[1:]  # trim leading '.'
            url = f'https://{resp.host}{href}'
            await destination.send(url)
        num = len(images) - 4
        if num > 0:
            s = 's' if num > 1 else ''
            message = f'{num} more image{s} at <{link}>'
            await destination.send(message)

    async def display_tumblr_images(self, link, destination):
        idx = 1
        async with self.get(link) as resp:
            root = etree.fromstring(await resp.read(), self.parser)
        if not str(resp.url).startswith(link): # explicit blog redirect
            async with self.bot.session.get(link) as resp: # somehow this doesn't get redirected?
                root = etree.fromstring(await resp.read(), self.parser)
            idx = 0
        images = root.xpath(self.tumblr_img_selector)
        for image in images[idx:4]:
            url = image.get('content')
            raw_url = re.sub(r'https?://\w+\.media',
                             'https://s3.amazonaws.com/data',
                            url)
            raw_url = re.sub(r'_\d+\.',
                             '_raw.',
                             raw_url)
            await destination.send(raw_url)
        num = len(images) - 4
        if num > 0:
            s = 's' if num > 1 else ''
            message = f'{num} more image{s} at <{link}>'
            await destination.send(message)

    @commands.command()
    async def twitter(self, ctx, enabled: bool=True):
        """Enable or disable sending non-previewed Twitter images."""
        await self.bot.config.set(ctx.guild.id, twitter=enabled)
        fmt = 'en' if enabled else 'dis'
        await ctx.send(f'Sending Twitter images {fmt}abled.')

def setup(bot):
    bot.add_cog(Twitter(bot))

<commit_msg>DRY, use context, send webm if gif too large<commit_after>from io import BytesIO
import json
import re

import aiohttp
from lxml import etree
import yaml

from discord.ext import commands
from discord import File, HTTPException

from utils.contextmanagers import get as _get

class Twitter:
    """Contains the capability to link images from tweets and other social media"""
    twitter_url_expr = re.compile(r'https?://(?:www\.)?twitter\.com/\S+/status/\d+')
    tweet_selector = ".//div[contains(@class, 'tweet permalink-tweet')]"
    twitter_img_selector = './/img[@data-aria-label-part]'

    pixiv_url_expr = re.compile(r'https?://(?:www\.)?pixiv\.net/member_illust\.php\??(?:&?[^=&]*=[^=&>\s]*)*')
    pixiv_img_selector = ".//img[@class='original-image']"
    pixiv_read_more_selector = ".//a[contains(@class, 'read-more')]"
    pixiv_manga_page_selector = ".//div[contains(@class, 'item-container')]/a"

    hiccears_url_expr = re.compile(r'https?://(?:www\.)?hiccears\.com/(?:(?:gallery)|(?:picture))\.php\?[gp]id=\d+')
    hiccears_link_selector = ".//div[contains(@class, 'row')]//a"
    hiccears_img_selector = ".//a[contains(@href, 'imgs')]"

    tumblr_url_expr = re.compile(r'https?://[\w-]+\.tumblr\.com/post/\d+')
    tumblr_img_selector = ".//meta[@property='og:image']"

    def __init__(self, bot):
        self.bot = bot
        self.bot.loop.create_task(self.__init())
        self.headers = {'User-Agent':
                        'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) '
                        'Gecko/20100101 Firefox/58.0'}
        with open('config/cookies.yaml') as fp:
            cookies = yaml.load(fp)
        self.session = aiohttp.ClientSession(loop=bot.loop, cookies=cookies)
        self.parser = etree.HTMLParser()
        names = (name.partition('_')[0] for name in vars(type(self)) if name.endswith('url_expr'))
        self.expr_dict = {getattr(self, f'{name}_url_expr'): getattr(self, f'display_{name}_images')
                          for name in names}

    async def __init(self):
        await self.bot.wait_until_ready()
        if not self.bot.user.bot:
            self.bot.unload_extension(__name__)

    def __unload(self):
        self.session.close()

    def get(self, *args, **kwargs):
        kwargs['headers'] = {**self.headers, **kwargs.get('headers', {})}
        return _get(self.session, *args, **kwargs)

    async def on_message(self, message):
        guild = message.guild
        if guild is None:
            return
        if message.author == guild.me:
            return
        if not (await self.bot.config.get(guild.id)).get('twitter'):
            return
        ctx = await self.bot.get_context(message)
        for expr, func in self.expr_dict.items():
            for link in expr.findall(message.content):
                await func(link, ctx)

    async def display_twitter_images(self, link, ctx):
        async with self.get(link) as resp:
            root = etree.fromstring(await resp.read(), self.parser)
        try:
            tweet = root.xpath(self.tweet_selector)[0]
        except IndexError:
            return
        for img_link in tweet.findall(self.twitter_img_selector)[1:]:
            url = img_link.get('src')
            await ctx.send(f'{url}:orig')

    async def display_pixiv_images(self, link, ctx):
        if 'mode' in link:
            link = re.sub('(?<=mode=)\w+', 'medium', link)
        else:
            link = f'{link}&mode=medium'
        link = link.replace('http://', 'https://')
        async with self.get(link) as resp:
            root = etree.fromstring(await resp.read(), self.parser)
        is_manga = root.xpath(self.pixiv_read_more_selector)
        if is_manga:
            manga_url = link.replace('medium', 'manga')
            heads = {'referer': manga_url}
            heads.update(self.headers)
            async with self.get(manga_url) as resp:
                root = etree.fromstring(await resp.read(), self.parser)
            pages = root.xpath(self.pixiv_manga_page_selector)
            for page in pages[:4]:
                href = page.get('href')
                fullsize_url = f'https://{resp.host}{href}'
                async with self.get(fullsize_url, headers=heads) as page_resp:
                    page_root = etree.fromstring(await page_resp.read(), self.parser)
                page_heads = heads.copy()
                page_heads['referer'] = fullsize_url
                img_url = page_root.find('.//img').get('src')
                filename = img_url.rpartition('/')[2]
                img = BytesIO()
                async with self.get(img_url, headers=heads) as img_resp:
                    async for chunk in img_resp.content.iter_any():
                        if chunk:
                            img.write(chunk)
                img.seek(0)
                file = File(img, filename)
                await ctx.send(file=file)
            num = len(pages) - 4
            if num > 0:
                s = 's' if num > 1 else ''
                message = f'{num} more image{s} at <{manga_url}>'
                await ctx.send(message)
        else:
            heads = {'referer': link}
            heads.update(self.headers)
            img_elem = root.xpath(self.pixiv_img_selector)
            if img_elem:
                await ctx.send('single image')
                img_elem = img_elem[0]
                url = img_elem.get('data-src')
                filename = url.rpartition('/')[2]
                img_request = self.get(url, headers=heads)
                async with img_request as resp:
                    content = await resp.read()
                img = BytesIO()
                img.write(content)
                img.seek(0)
                file = File(img, filename)
                await ctx.send(file=file)
            else:
                msg = await ctx.send('Fetching gif...')
                file = await self.get_ugoira(link)
                try:
                    await ctx.send(file=file)
                except HTTPException:
                    await msg.edit(content='Gif too large, fetching webm...')
                    file = await self.get_ugoira(link, fmt='webm')
                    await ctx.send(file=file)
                await msg.delete()

    async def get_ugoira(self, link, fmt='gif'):
        params = {
            'url': link,
            'format': fmt,
        }
        conv_url = 'http://ugoira.dataprocessingclub.org/convert'
        async with self.get(conv_url, params=params, timeout=None) as resp:
            text = await resp.text()
        url = json.loads(text)['url']
        img = BytesIO()
        async with self.get(url) as resp:
            async for block in resp.content.iter_any():
                if not block:
                    break
                img.write(block)
        img.seek(0)
        name = url.rpartition('/')[2]
        return File(img, name)

    async def display_hiccears_images(self, link, ctx):
        async with self.get(link) as resp:
            root = etree.fromstring(await resp.read(), self.parser)
        single_image = root.xpath(self.hiccears_img_selector)
        if single_image:
            a = single_image[0]
            href = a.get('href').lstrip('.')
            url = f'https://{resp.host}{href}'
            await ctx.send(url)
            return

        images = root.xpath(self.hiccears_link_selector)
        for image in images[:4]:
            href = image.get('href')
            url = f'https://{resp.host}{href[1:]}'
            async with self.get(url) as page_resp:
                page = etree.fromstring(await page_resp.read(), self.parser)
            a = page.xpath(self.hiccears_img_selector)[0]
            href = a.get('href')[1:]  # trim leading '.'
            url = f'https://{resp.host}{href}'
            await ctx.send(url)
        num = len(images) - 4
        if num > 0:
            s = 's' if num > 1 else ''
            message = f'{num} more image{s} at <{link}>'
            await ctx.send(message)

    async def display_tumblr_images(self, link, ctx):
        idx = 1
        async with self.get(link) as resp:
            root = etree.fromstring(await resp.read(), self.parser)
        if not str(resp.url).startswith(link): # explicit blog redirect
            async with self.bot.session.get(link) as resp: # somehow this doesn't get redirected?
                root = etree.fromstring(await resp.read(), self.parser)
            idx = 0
        images = root.xpath(self.tumblr_img_selector)
        for image in images[idx:4]:
            url = image.get('content')
            raw_url = re.sub(r'https?://\w+\.media',
                             'https://s3.amazonaws.com/data',
                            url)
            raw_url = re.sub(r'_\d+\.',
                             '_raw.',
                             raw_url)
            await ctx.send(raw_url)
        num = len(images) - 4
        if num > 0:
            s = 's' if num > 1 else ''
            message = f'{num} more image{s} at <{link}>'
            await ctx.send(message)

    @commands.command()
    async def twitter(self, ctx, enabled: bool=True):
        """Enable or disable sending non-previewed Twitter images."""
        await self.bot.config.set(ctx.guild.id, twitter=enabled)
        fmt = 'en' if enabled else 'dis'
        await ctx.send(f'Sending Twitter images {fmt}abled.')

def setup(bot):
    bot.add_cog(Twitter(bot))

<|endoftext|>


<commit_before>#!/usr/bin/env python

import sys
import subprocess

def main(args):
    # Usage instructions
    if len(args) < 6 or len(args) > 7:
        print("Usage: {} <server> <client> <config> <port> <logfile> [<client_N>]".format(args[0]))
        return

    # Give meaningful names to arguments
    server, client = args[1], args[2]
    config, port   = args[3], args[4]
    logfile        = args[5]

    # Make sure argument has some default value
    client_n = int(args[6]) if len(args) == 7 else 100

    # Create a server process
    subprocess.Popen([server, config, port, logfile])

    # Create N client processes
    for i in range(client_n):
        subprocess.Popen([client, "localhost:" + port])

if __name__ == "__main__":
    main(sys.argv)
<commit_msg>Quick fix - Make all clients quiet<commit_after>#!/usr/bin/env python

import os
import sys
import subprocess

def main(args):
    # Usage instructions
    if len(args) < 6 or len(args) > 7:
        print("Usage: {} <server> <client> <config> <port> <logfile> [<client_N>]".format(args[0]))
        return

    # Give meaningful names to arguments
    server, client = args[1], args[2]
    config, port   = args[3], args[4]
    logfile        = args[5]

    # Make sure argument has some default value
    client_n = int(args[6]) if len(args) == 7 else 100

    # Create a server process
    subprocess.Popen([server, config, port, logfile])

    # Create N client processes
    for i in range(client_n):
        subprocess.Popen([client, "localhost:" + port], stdout=open(os.devnull, 'wb'))

if __name__ == "__main__":
    main(sys.argv)
<|endoftext|>


<commit_before>import sys
import time
import json
import discord
from discord.ext import commands
from random import choice as rchoice
startepoch = time.time()
config = json.load(open('config.json'))
class Utility:
  def __init__(self, bot):
    self.bot = bot
    self.support = 'https://discord.gg/PEW4wx9'

  @commands.command()
  async def uptime(self, ctx):
    """Shows uptime of lolbot"""
    upEm = discord.Embed(title='Uptime', colour=0x690E8)
    startedOn = time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime(startepoch))
    #timeUp = get_up()
    nowEpoch = time.time()
    upEpoch = nowEpoch - startepoch
    upEm.add_field(name='Started on', value=startedOn)
    upEm.add_field(name='Uptime', value=time.strftime('%H:%M:%S', time.localtime(upEpoch)))
    try:
      await ctx.send(embed=upEm)
    except Exception as ex:
      await ctx.send('Something broke - sorry!')

  @commands.command()
  async def stats(self, ctx):
    """A few stats."""
    # get_owner = bot.get_user_info(config['ownerid'])
    statInfo = await ctx.bot.application_info()
    statEmbed = discord.Embed(title='Stats', description='This bot is'
   ' powered by [lolbot](https://github.com/xshotD/lolbot), a fast and powerful '
   'Python bot.', colour=0x690E8)
    statEmbed.add_field(name='Owner', value=statInfo.owner.mention + '('
    + str(statInfo.owner) + ' - ID: ' + str(statInfo.owner.id) + ')')
    statEmbed.add_field(name='Python', value=sys.version)
    statEmbed.add_field(name='discord.py', value=discord.__version__)
    statEmbed.add_field(name='Servers', value=len(self.bot.guilds))
    statPool = ['What have you done now?', 'Why should I do this again?', 'Oh..',
    'Where did the RAM go?', 'grumble grumble', 'Please hold.', 'No, just, no.',
    'Have you tried rebooting?', 'memework makes the dreamwork!']
    statEmbed.set_footer(text=rchoice(statPool))
    try:
      await ctx.send(embed=statEmbed)
    except:
      await ctx.send('Sorry, I can\'t send the Embed.')
      await ctx.send('Maybe I don\'t have Embed Links permission?')
    else:
      pass

  @commands.command()
  async def ping(self, ctx):
      """Does exactly what you think it does"""
      before = time.monotonic()
      ping = await ctx.send('ping')
      after = time.monotonic()
      msLogic = round((after - before) * 1000, 2)
      ms = discord.Embed(title='Pong.', description='Response time was'
      'a nice' + f'{msLogic}ms' + '!')
      await ping.edit(embed=ms)

  @commands.command()
  async def invite(self, ctx):
      """Gives a invite for the bot (and also the official server)"""
      invEmb = discord.Embed(colour=0x690E8)
      invEmb.add_field(name='Invite lolbot', value='[Click here]'
      '(' + discord.utils.oauth_url(config['botid']) + ')')
      invEmb.add_field(name='Official server', value=str(self.support))
      await ctx.send(embed=invEmb)

def setup(bot):
  bot.add_cog(Utility(bot))
<commit_msg>[cogs, utility] make ping a embed x2<commit_after>import sys
import time
import json
import discord
from discord.ext import commands
from random import choice as rchoice
startepoch = time.time()
config = json.load(open('config.json'))
class Utility:
  def __init__(self, bot):
    self.bot = bot
    self.support = 'https://discord.gg/PEW4wx9'

  @commands.command()
  async def uptime(self, ctx):
    """Shows uptime of lolbot"""
    upEm = discord.Embed(title='Uptime', colour=0x690E8)
    startedOn = time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime(startepoch))
    #timeUp = get_up()
    nowEpoch = time.time()
    upEpoch = nowEpoch - startepoch
    upEm.add_field(name='Started on', value=startedOn)
    upEm.add_field(name='Uptime', value=time.strftime('%H:%M:%S', time.localtime(upEpoch)))
    try:
      await ctx.send(embed=upEm)
    except Exception as ex:
      await ctx.send('Something broke - sorry!')

  @commands.command()
  async def stats(self, ctx):
    """A few stats."""
    # get_owner = bot.get_user_info(config['ownerid'])
    statInfo = await ctx.bot.application_info()
    statEmbed = discord.Embed(title='Stats', description='This bot is'
   ' powered by [lolbot](https://github.com/xshotD/lolbot), a fast and powerful '
   'Python bot.', colour=0x690E8)
    statEmbed.add_field(name='Owner', value=statInfo.owner.mention + '('
    + str(statInfo.owner) + ' - ID: ' + str(statInfo.owner.id) + ')')
    statEmbed.add_field(name='Python', value=sys.version)
    statEmbed.add_field(name='discord.py', value=discord.__version__)
    statEmbed.add_field(name='Servers', value=len(self.bot.guilds))
    statPool = ['What have you done now?', 'Why should I do this again?', 'Oh..',
    'Where did the RAM go?', 'grumble grumble', 'Please hold.', 'No, just, no.',
    'Have you tried rebooting?', 'memework makes the dreamwork!']
    statEmbed.set_footer(text=rchoice(statPool))
    try:
      await ctx.send(embed=statEmbed)
    except:
      await ctx.send('Sorry, I can\'t send the Embed.')
      await ctx.send('Maybe I don\'t have Embed Links permission?')
    else:
      pass

  @commands.command()
  async def ping(self, ctx):
      """Does exactly what you think it does"""
      before = time.monotonic()
      ping = await ctx.send('ping')
      after = time.monotonic()
      msLogic = round((after - before) * 1000, 2)
      ms = discord.Embed(title='Pong.', description='Response time was'
      'a nice' + f'{msLogic}ms' + ' !', colour=0x690E8)
      await ping.edit(embed=ms)

  @commands.command()
  async def invite(self, ctx):
      """Gives a invite for the bot (and also the official server)"""
      invEmb = discord.Embed(colour=0x690E8)
      invEmb.add_field(name='Invite lolbot', value='[Click here]'
      '(' + discord.utils.oauth_url(config['botid']) + ')')
      invEmb.add_field(name='Official server', value=str(self.support))
      await ctx.send(embed=invEmb)

def setup(bot):
  bot.add_cog(Utility(bot))
<|endoftext|>