Merge remote-tracking branch 'upstream/develop' into develop

This commit is contained in:
scummboy 2016-02-12 14:13:14 +00:00
commit be19c3dc58
4 changed files with 306 additions and 59 deletions

View File

@ -12,16 +12,11 @@ import glob
import re import re
import aiohttp import aiohttp
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
import __main__
import json import json
if not discord.opus.is_loaded(): if not discord.opus.is_loaded():
discord.opus.load_opus('libopus-0.dll') discord.opus.load_opus('libopus-0.dll')
main_path = os.path.dirname(os.path.realpath(__main__.__file__))
settings = {"VOLUME" : 0.5, "MAX_LENGTH" : 3700, "QUEUE_MODE" : True}
youtube_dl_options = { youtube_dl_options = {
'format': 'bestaudio/best', 'format': 'bestaudio/best',
'extractaudio': True, 'extractaudio': True,
@ -40,6 +35,7 @@ class Audio:
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
self.music_player = EmptyPlayer() self.music_player = EmptyPlayer()
self.settings = fileIO("data/audio/settings.json", "load")
self.queue_mode = False self.queue_mode = False
self.queue = [] self.queue = []
self.playlist = [] self.playlist = []
@ -63,10 +59,10 @@ class Audio:
if await self.check_voice(msg.author, msg): if await self.check_voice(msg.author, msg):
if self.is_playlist_valid([link]): # reusing a function if self.is_playlist_valid([link]): # reusing a function
if await self.is_alone_or_admin(msg.author): if await self.is_alone_or_admin(msg.author):
self.queue = [] self.queue = []
self.playlist = []
self.current = -1 self.current = -1
await self.play_video(link) self.playlist = [link]
self.music_player.stop()
else: else:
self.playlist = [] self.playlist = []
self.current = -1 self.current = -1
@ -79,8 +75,10 @@ class Audio:
async def song(self): async def song(self):
"""Shows song title """Shows song title
""" """
if self.downloader["TITLE"]: if self.downloader["TITLE"] and "localtracks" not in self.downloader["TITLE"]:
await self.bot.say(self.downloader["TITLE"]) url = ""
if self.downloader["URL"]: url = 'Link : "' + self.downloader["URL"] + '"'
await self.bot.say(self.downloader["TITLE"] + "\n" + url)
else: else:
await self.bot.say("No title available.") await self.bot.say("No title available.")
@ -183,10 +181,8 @@ class Audio:
msg = ctx.message msg = ctx.message
if self.music_player.is_playing(): if self.music_player.is_playing():
if await self.is_alone_or_admin(msg.author): if await self.is_alone_or_admin(msg.author):
if self.playlist: self.current = -1
self.playlist = self.playlist[[self.current]] self.playlist = [self.downloader["URL"]]
elif self.queue:
self.playlist = self.playlist[[self.queue[0]]]
await self.bot.say("I will play this song on repeat.") await self.bot.say("I will play this song on repeat.")
else: else:
await self.bot.say("I'm in queue mode. Controls are disabled if you're in a room with multiple people.") await self.bot.say("I'm in queue mode. Controls are disabled if you're in a room with multiple people.")
@ -253,7 +249,9 @@ class Audio:
await self.bot.say("I'm already playing a playlist.") await self.bot.say("I'm already playing a playlist.")
async def is_alone_or_admin(self, author): #Direct control. fix everything async def is_alone_or_admin(self, author): #Direct control. fix everything
if not settings["QUEUE_MODE"]: if not self.settings["QUEUE_MODE"]:
return True
elif author.id == checks.settings["OWNER"]:
return True return True
elif discord.utils.get(author.roles, name=checks.settings["ADMIN_ROLE"]) is not None: elif discord.utils.get(author.roles, name=checks.settings["ADMIN_ROLE"]) is not None:
return True return True
@ -325,7 +323,7 @@ class Audio:
"""Changes audio module settings""" """Changes audio module settings"""
if ctx.invoked_subcommand is None: if ctx.invoked_subcommand is None:
msg = "```" msg = "```"
for k, v in settings.items(): for k, v in self.settings.items():
msg += str(k) + ": " + str(v) + "\n" msg += str(k) + ": " + str(v) + "\n"
msg += "\nType help audioset to see the list of commands.```" msg += "\nType help audioset to see the list of commands.```"
await self.bot.say(msg) await self.bot.say(msg)
@ -333,35 +331,32 @@ class Audio:
@audioset.command(name="queue") @audioset.command(name="queue")
async def queueset(self, status : str): async def queueset(self, status : str):
"""Enables/disables queue""" """Enables/disables queue"""
global settings
status = status.lower() status = status.lower()
if status == "on" or status == "true": if status == "on" or status == "true":
settings["QUEUE_MODE"] = True self.settings["QUEUE_MODE"] = True
await self.bot.say("Queue mode is now on.") await self.bot.say("Queue mode is now on.")
elif status == "off" or status == "false": elif status == "off" or status == "false":
settings["QUEUE_MODE"] = False self.settings["QUEUE_MODE"] = False
await self.bot.say("Queue mode is now off.") await self.bot.say("Queue mode is now off.")
else: else:
await self.bot.say("Queue status can be either on or off.") await self.bot.say("Queue status can be either on or off.")
return return
self.save_settings() fileIO("data/audio/settings.json", "save", self.settings)
@audioset.command() @audioset.command()
async def maxlength(self, length : int): async def maxlength(self, length : int):
"""Maximum track length for requested links""" """Maximum track length for requested links"""
global settings self.settings["MAX_LENGTH"] = length
settings["MAX_LENGTH"] = length
await self.bot.say("Maximum length is now " + str(length) + " seconds.") await self.bot.say("Maximum length is now " + str(length) + " seconds.")
self.save_settings() fileIO("data/audio/settings.json", "save", self.settings)
@audioset.command() @audioset.command()
async def volume(self, level : float): async def volume(self, level : float):
"""Sets the volume (0-1)""" """Sets the volume (0-1)"""
global settings
if level >= 0 and level <= 1: if level >= 0 and level <= 1:
settings["VOLUME"] = level self.settings["VOLUME"] = level
await self.bot.say("Volume is now set at " + str(level) + ". It will take effect after the current track.") await self.bot.say("Volume is now set at " + str(level) + ". It will take effect after the current track.")
self.save_settings() fileIO("data/audio/settings.json", "save", self.settings)
else: else:
await self.bot.say("Volume must be between 0 and 1. Example: 0.40") await self.bot.say("Volume must be between 0 and 1. Example: 0.40")
@ -379,7 +374,7 @@ class Audio:
if self.downloader["ID"]: if self.downloader["ID"]:
try: try:
self.music_player.stop() self.music_player.stop()
self.music_player = self.bot.voice.create_ffmpeg_player(path + self.downloader["ID"], options='''-filter:a "volume={}"'''.format(settings["VOLUME"])) self.music_player = self.bot.voice.create_ffmpeg_player(path + self.downloader["ID"], options='''-filter:a "volume={}"'''.format(self.settings["VOLUME"]))
self.music_player.start() self.music_player.start()
if path != "": await self.bot.change_status(discord.Game(name=self.downloader["TITLE"])) if path != "": await self.bot.change_status(discord.Game(name=self.downloader["TITLE"]))
except discord.errors.ClientException: except discord.errors.ClientException:
@ -448,7 +443,7 @@ class Audio:
self.downloader["DOWNLOADING"] = True self.downloader["DOWNLOADING"] = True
yt = youtube_dl.YoutubeDL(youtube_dl_options) yt = youtube_dl.YoutubeDL(youtube_dl_options)
v = yt.extract_info(url, download=False) v = yt.extract_info(url, download=False)
if v["duration"] > settings["MAX_LENGTH"]: raise MaximumLength("Track exceeded maximum length. See help audioset maxlength") if v["duration"] > self.settings["MAX_LENGTH"]: raise MaximumLength("Track exceeded maximum length. See help audioset maxlength")
if not os.path.isfile("data/audio/cache/" + v["id"]): if not os.path.isfile("data/audio/cache/" + v["id"]):
v = yt.extract_info(url, download=True) v = yt.extract_info(url, download=True)
audio.downloader = {"DONE" : True, "TITLE" : v["title"], "ID" : v["id"], "URL" : url, "DURATION" : v["duration"], "DOWNLOADING" : False} #Errors out here if invalid link audio.downloader = {"DONE" : True, "TITLE" : v["title"], "ID" : v["id"], "URL" : url, "DURATION" : v["duration"], "DOWNLOADING" : False} #Errors out here if invalid link
@ -564,10 +559,6 @@ class Audio:
except: except:
return False return False
def save_settings(self):
with open(main_path + "/data/audio/settings.json", "w") as f:
f.write(json.dumps(settings))
class EmptyPlayer(): #dummy player class EmptyPlayer(): #dummy player
def __init__(self): def __init__(self):
pass pass
@ -591,24 +582,26 @@ def check_folders():
print("Creating " + folder + " folder...") print("Creating " + folder + " folder...")
os.makedirs(folder) os.makedirs(folder)
def check_files(n): def check_files():
if not os.path.isfile(main_path + "/data/audio/settings.json"):
settings = {"VOLUME" : 0.5, "MAX_LENGTH" : 3700, "QUEUE_MODE" : True}
if not os.path.isfile("data/audio/settings.json"):
print("Creating default audio settings.json...") print("Creating default audio settings.json...")
n.save_settings() fileIO("data/audio/settings.json", "save", settings)
allowed = ["^(https:\/\/www\\.youtube\\.com\/watch\\?v=...........*)", "^(https:\/\/youtu.be\/...........*)", allowed = ["^(https:\/\/www\\.youtube\\.com\/watch\\?v=...........*)", "^(https:\/\/youtu.be\/...........*)",
"^(https:\/\/youtube\\.com\/watch\\?v=...........*)", "^(https:\/\/soundcloud\\.com\/.*)"] "^(https:\/\/youtube\\.com\/watch\\?v=...........*)", "^(https:\/\/soundcloud\\.com\/.*)"]
if not os.path.isfile(main_path + "/data/audio/accepted_links.json"): if not os.path.isfile("data/audio/accepted_links.json"):
print("Creating accepted_links.json...") print("Creating accepted_links.json...")
with open(main_path + "/data/audio/accepted_links.json", "w") as f: fileIO("data/audio/accepted_links.json", "save", allowed)
f.write(json.dumps(allowed))
def setup(bot): def setup(bot):
check_folders()
check_files()
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
n = Audio(bot) n = Audio(bot)
check_folders()
check_files(n)
loop.create_task(n.queue_manager()) loop.create_task(n.queue_manager())
bot.add_listener(n.incoming_messages, "on_message") bot.add_listener(n.incoming_messages, "on_message")
bot.add_cog(n) bot.add_cog(n)

235
cogs/economy.py Normal file
View File

@ -0,0 +1,235 @@
import discord
from discord.ext import commands
from .utils.dataIO import fileIO
from .utils import checks
from random import randint
import os
import time
slot_payouts = """Slot machine payouts:
:two: :two: :six: Bet * 5000
:four_leaf_clover: :four_leaf_clover: :four_leaf_clover: +1000
:cherries: :cherries: :cherries: +800
:two: :six: Bet * 4
:cherries: :cherries: Bet * 3
Three symbols: +500
Two symbols: Bet * 2"""
class Economy:
"""Economy
Get rich and have fun with imaginary currency!"""
def __init__(self, bot):
self.bot = bot
self.bank = fileIO("data/economy/bank.json", "load")
self.settings = fileIO("data/economy/settings.json", "load")
self.payday_register = {}
@commands.group(name="bank", pass_context=True)
async def _bank(self, ctx):
"""Bank operations"""
if ctx.invoked_subcommand is None:
await self.bot.say("Type help bank for info.")
@_bank.command(pass_context=True, no_pm=True)
async def register(self, ctx):
"""Registers an account at the Twentysix bank"""
user = ctx.message.author
if user.id not in self.bank:
self.bank[user.id] = {"name" : user.name, "balance" : 100}
fileIO("data/economy/bank.json", "save", self.bank)
await self.bot.say("{} `Account opened. Current balance: {}`".format(user.mention, str(self.check_balance(user.id))))
else:
await self.bot.say("{} `You already have an account at the Twentysix bank.`".format(user.mention))
@_bank.command(pass_context=True)
async def balance(self, ctx):
"""Shows your current balance"""
user = ctx.message.author
if self.account_check(user.id):
await self.bot.say("{} `Your balance is: {}`".format(user.mention, str(self.check_balance(user.id))))
else:
await self.bot.say("{} `You don't have an account at the Twentysix bank. Type !register to open one.`".format(user.mention, str(self.check_balance(user.id))))
@commands.command(pass_context=True, no_pm=True)
async def payday(self, ctx):
"""Get some free credits"""
author = ctx.message.author
id = author.id
if self.account_check(id):
if id in self.payday_register:
if abs(self.payday_register[id] - int(time.perf_counter())) >= self.settings["PAYDAY_TIME"]:
self.add_money(id, self.settings["PAYDAY_CREDITS"])
self.payday_register[id] = int(time.perf_counter())
await self.bot.say("{} `Here, take some credits. Enjoy! (+{} credits!)`".format(author.mention, str(self.settings["PAYDAY_CREDITS"])))
else:
await self.bot.say("{} `Too soon. You have to wait {} seconds between each payday.`".format(author.mention, str(self.settings["PAYDAY_TIME"])))
else:
self.payday_register[id] = int(time.perf_counter())
self.add_money(id, self.settings["PAYDAY_CREDITS"])
await self.bot.say("{} `Here, take some credits. Enjoy! (+{} credits!)`".format(author.mention, str(self.settings["PAYDAY_CREDITS"])))
else:
await self.bot.say("{} `You need an account to receive credits. (!economy)`".format(author.mention))
@commands.command(pass_context=True)
async def payouts(self, ctx):
"""Shows slot machine payouts"""
await self.bot.send_message(ctx.message.author, slot_payouts)
@commands.command(pass_context=True, no_pm=True)
async def slot(self, ctx, bid : int):
"""Play the slot machine"""
author = ctx.message.author
if self.enough_money(author.id, bid):
if bid >= self.settings["SLOT_MIN"] and bid <= self.settings["SLOT_MAX"]:
await self.slot_machine(ctx.message, bid)
else:
await self.bot.say("{0} `Bid must be between {1} and {2}.`".format(author.mention, self.settings["SLOT_MIN"], self.settings["SLOT_MAX"]))
else:
await self.bot.say("{0} `You need an account with enough funds to play the slot machine.`".format(author.mention))
async def slot_machine(self, message, bid):
reel_pattern = [":cherries:", ":cookie:", ":two:", ":four_leaf_clover:", ":cyclone:", ":sunflower:", ":six:", ":mushroom:", ":heart:", ":snowflake:"]
padding_before = [":mushroom:", ":heart:", ":snowflake:"] # padding prevents index errors
padding_after = [":cherries:", ":cookie:", ":two:"]
reel = padding_before + reel_pattern + padding_after
reels = []
for i in range(0, 3):
n = randint(3,12)
reels.append([reel[n - 1], reel[n], reel[n + 1]])
line = [reels[0][1], reels[1][1], reels[2][1]]
display_reels = " " + reels[0][0] + " " + reels[1][0] + " " + reels[2][0] + "\n"
display_reels += ">" + reels[0][1] + " " + reels[1][1] + " " + reels[2][1] + "\n"
display_reels += " " + reels[0][2] + " " + reels[1][2] + " " + reels[2][2] + "\n"
if line[0] == ":two:" and line[1] == ":two:" and line[2] == ":six:":
bid = bid * 5000
await self.bot.send_message(message.channel, "{}{} `226! Your bet is multiplied * 5000! {}!` ".format(display_reels, message.author.mention, str(bid)))
elif line[0] == ":four_leaf_clover:" and line[1] == ":four_leaf_clover:" and line[2] == ":four_leaf_clover:":
bid += 1000
await self.bot.send_message(message.channel, "{}{} `Three FLC! +1000!` ".format(display_reels, message.author.mention))
elif line[0] == ":cherries:" and line[1] == ":cherries:" and line[2] == ":cherries:":
bid += 800
await self.bot.send_message(message.channel, "{}{} `Three cherries! +800!` ".format(display_reels, message.author.mention))
elif line[0] == line[1] == line[2]:
bid += 500
await self.bot.send_message(message.channel, "{}{} `Three symbols! +500!` ".format(display_reels, message.author.mention))
elif line[0] == ":two:" and line[1] == ":six:" or line[1] == ":two:" and line[2] == ":six:":
bid = bid * 4
await self.bot.send_message(message.channel, "{}{} `26! Your bet is multiplied * 4! {}!` ".format(display_reels, message.author.mention, str(bid)))
elif line[0] == ":cherries:" and line[1] == ":cherries:" or line[1] == ":cherries:" and line[2] == ":cherries:":
bid = bid * 3
await self.bot.send_message(message.channel, "{}{} `Two cherries! Your bet is multiplied * 3! {}!` ".format(display_reels, message.author.mention, str(bid)))
elif line[0] == line[1] or line[1] == line[2]:
bid = bid * 2
await self.bot.send_message(message.channel, "{}{} `Two symbols! Your bet is multiplied * 2! {}!` ".format(display_reels, message.author.mention, str(bid)))
else:
await self.bot.send_message(message.channel, "{}{} `Nothing! Lost bet.` ".format(display_reels, message.author.mention))
self.withdraw_money(message.author.id, bid)
await self.bot.send_message(message.channel, "`Credits left: {}`".format(str(self.check_balance(message.author.id))))
return True
self.add_money(message.author.id, bid)
await self.bot.send_message(message.channel, "`Current credits: {}`".format(str(self.check_balance(message.author.id))))
@commands.group(pass_context=True, no_pm=True)
@checks.mod_or_permissions()
async def economyset(self, ctx):
"""Changes economy module settings"""
if ctx.invoked_subcommand is None:
msg = "```"
for k, v in self.settings.items():
msg += str(k) + ": " + str(v) + "\n"
msg += "\nType help economyset to see the list of commands.```"
await self.bot.say(msg)
@economyset.command()
async def slotmin(self, bid : int):
"""Minimum slot machine bid"""
self.settings["SLOT_MIN"] = bid
await self.bot.say("Minimum bid is now " + str(bid) + " credits.")
fileIO("data/economy/settings.json", "save", self.settings)
@economyset.command()
async def slotmax(self, bid : int):
"""Maximum slot machine bid"""
self.settings["SLOT_MAX"] = bid
await self.bot.say("Maximum bid is now " + str(bid) + " credits.")
fileIO("data/economy/settings.json", "save", self.settings)
@economyset.command()
async def paydaytime(self, seconds : int):
"""Seconds between each payday"""
self.settings["PAYDAY_TIME"] = seconds
await self.bot.say("Value modified. At least " + str(seconds) + " seconds must pass between each payday.")
fileIO("data/economy/settings.json", "save", self.settings)
@economyset.command()
async def paydaycredits(self, credits : int):
"""Credits earned each payday"""
self.settings["PAYDAY_CREDITS"] = credits
await self.bot.say("Every payday will now give " + str(credits) + " credits.")
fileIO("data/economy/settings.json", "save", self.settings)
def account_check(self, id):
if id in self.bank:
return True
else:
return False
def check_balance(self, id):
if self.account_check(id):
return self.bank[id]["balance"]
else:
return False
def add_money(self, id, amount):
if self.account_check(id):
self.bank[id]["balance"] = self.bank[id]["balance"] + int(amount)
fileIO("data/economy/bank.json", "save", self.bank)
else:
return False
def withdraw_money(self, id, amount):
if self.account_check(id):
if self.bank[id]["balance"] >= int(amount):
self.bank[id]["balance"] = self.bank[id]["balance"] - int(amount)
fileIO("data/economy/bank.json", "save", self.bank)
else:
return False
else:
return False
def enough_money(self, id, amount):
if self.account_check(id):
if self.bank[id]["balance"] >= int(amount):
return True
else:
return False
else:
return False
def check_folders():
if not os.path.exists("data/economy"):
print("Creating data/economy folder...")
os.makedirs("data/economy")
def check_files():
settings = {"PAYDAY_TIME" : 300, "PAYDAY_CREDITS" : 120, "SLOT_MIN" : 5, "SLOT_MAX" : 100}
f = "data/economy/settings.json"
if not fileIO(f, "check"):
print("Creating default economy's settings.json...")
fileIO(f, "save", settings)
f = "data/economy/bank.json"
if not fileIO(f, "check"):
print("Creating empty bank.json...")
fileIO(f, "save", {})
def setup(bot):
check_folders()
check_files()
bot.add_cog(Economy(bot))

View File

@ -1,7 +1,6 @@
import discord import discord
from discord.ext import commands from discord.ext import commands
from random import randint from random import randint
from imgurpython import ImgurClient
import aiohttp import aiohttp
import random import random
@ -16,9 +15,10 @@ class Image:
@commands.command(no_pm=True) @commands.command(no_pm=True)
async def imgur(self, *text): async def imgur(self, *text):
"""Retrieves a random imgur picture. """Retrieves a random imgur picture
imgur search [keyword] - retrieves first hit of search query.
imgur [subreddit section] [top or new] - retrieves top 3 hottest or latest pictures of today for given a subreddit section, e.g. 'funny'.""" imgur search [keyword] - Retrieves first hit of search query.
imgur [subreddit section] [top or new] - Retrieves top 3 hottest or latest pictures of today for given a subreddit section, e.g. 'funny'."""
imgurclient = ImgurClient("1fd3ef04daf8cab", "f963e574e8e3c17993c933af4f0522e1dc01e230") imgurclient = ImgurClient("1fd3ef04daf8cab", "f963e574e8e3c17993c933af4f0522e1dc01e230")
if text == (): if text == ():
rand = randint(0, 59) #60 results per generated page rand = randint(0, 59) #60 results per generated page
@ -31,22 +31,27 @@ class Image:
else: else:
await self.bot.say(items[0].link) await self.bot.say(items[0].link)
elif text[0] != (): elif text[0] != ():
if text[1] == "top": try:
imgSort = "top" if text[1] == "top":
elif text[1] == "new": imgSort = "top"
imgSort = "time" elif text[1] == "new":
else: imgSort = "time"
await self.bot.say("Only top or new is a valid subcommand.") else:
return await self.bot.say("Only top or new is a valid subcommand.")
items = imgurclient.subreddit_gallery(text[0], sort=imgSort, window='day', page=0) return
if (len(items) < 3): items = imgurclient.subreddit_gallery(text[0], sort=imgSort, window='day', page=0)
await self.bot.say("This subreddit section does not exist, try 'funny'") if (len(items) < 3):
else: await self.bot.say("This subreddit section does not exist, try 'funny'")
await self.bot.say("{} {} {}".format(items[0].link, items[1].link, items[2].link)) else:
await self.bot.say("{} {} {}".format(items[0].link, items[1].link, items[2].link))
except:
await self.bot.say("Type help imgur for details.")
@commands.command(no_pm=True) @commands.command(no_pm=True)
async def gif(self, *text): async def gif(self, *text):
""" gif [keyword] - retrieves first search result from giphy """ """Retrieves first search result from giphy
gif [keyword]"""
if len(text) > 0: if len(text) > 0:
if len(text[0]) > 1 and len(text[0]) < 20: if len(text[0]) > 1 and len(text[0]) < 20:
try: try:
@ -68,7 +73,9 @@ class Image:
@commands.command(no_pm=True) @commands.command(no_pm=True)
async def gifr(self, *text): async def gifr(self, *text):
""" gifr [keyword] - retrieves a random gif from a giphy search """ """Retrieves a random gif from a giphy search
gifr [keyword]"""
random.seed() random.seed()
if len(text) > 0: if len(text) > 0:
if len(text[0]) > 1 and len(text[0]) < 20: if len(text[0]) > 1 and len(text[0]) < 20:
@ -88,7 +95,18 @@ class Image:
else: else:
await self.bot.say("Invalid search.") await self.bot.say("Invalid search.")
else: else:
await self.bot.say("gif [text]") await self.bot.say("gifr [text]")
class ModuleNotFound(Exception):
def __init__(self, m):
self.message = m
def __str__(self):
return self.message
def setup(bot): def setup(bot):
global ImgurClient
try:
from imgurpython import ImgurClient
except:
raise ModuleNotFound("imgurpython is not installed. Do 'pip3 install imgurpython' to use this cog.")
bot.add_cog(Image(bot)) bot.add_cog(Image(bot))

1
red.py
View File

@ -187,6 +187,7 @@ async def setprefix(*text):
@bot.command(name="uptime") @bot.command(name="uptime")
async def _uptime(): async def _uptime():
"""Shows Red's uptime"""
up = abs(bot.uptime - int(time.perf_counter())) up = abs(bot.uptime - int(time.perf_counter()))
up = str(datetime.timedelta(seconds=up)) up = str(datetime.timedelta(seconds=up))
await bot.say("`Uptime: {}`".format(up)) await bot.say("`Uptime: {}`".format(up))