1
0
Fork 0
mirror of synced 2024-05-07 06:02:24 +12:00

Complete modification to use cogs

This commit is contained in:
phxntxm 2016-07-08 20:27:19 -05:00
parent ee03eb3b1b
commit 2bde1ce936
9 changed files with 605 additions and 639 deletions

638
bot.py
View file

@ -1,104 +1,35 @@
#!/usr/local/bin/python3.5
import asyncio
import json
import os
import random
import re
import subprocess
import sys
import urllib.parse
import urllib.request
import yaml
from threading import Timer
import discord
import pymysql.cursors
from discord.ext import commands
from cogs.utils import config
import playlist
extensions = ['cogs.interaction',
'cogs.core',
'cogs.mod',
'cogs.owner',
'cogs.stats',
'cogs.playlist']
with open("/home/phxntx5/public_html/bot/config.yml", "r") as f:
global_config = yaml.load(f)
botDescription = global_config.get("description")
commandPrefix = global_config.get("command_prefix")
# Custom predicates
def isOwner():
def predicate(ctx):
return ctx.message.author.id == ownerID
return commands.check(predicate)
def isMod():
def predicate(ctx):
return ctx.message.author.top_role.permissions.kick_members
return commands.check(predicate)
def isAdmin():
def predicate(ctx):
return ctx.message.author.top_role.permissions.manage_server
return commands.check(predicate)
def isPM():
def predicate(ctx):
return ctx.message.channel.is_private
return commands.check(predicate)
def battled():
def predicate(ctx):
return ctx.message.author == battleP2
return commands.check(predicate)
bot = commands.Bot(command_prefix=commandPrefix, description=botDescription)
music = playlist.Music(bot)
bot.add_cog(music)
# Turn battling off, reset users
def battlingOff():
global battleP1
global battleP2
global battling
battling = False
battleP1 = ""
battleP2 = ""
bot = commands.Bot(command_prefix=config.commandPrefix, description=config.botDescription, pm_help="True")
# Bot event overrides
@bot.event
async def on_ready():
# Change the status upon connection to the default status
game = discord.Game(name=defaultStatus, type=0)
game = discord.Game(name=config.defaultStatus, type=0)
await bot.change_status(game)
cursor = connection.cursor()
cursor = config.connection.cursor()
'''success = checkSetup(cursor)
if success=="Error: default_db":
fmt = "The bot ran into an error while checking for the default database information."
await bot.send_message(determineId(ownerID),fmt)
elif success="Error: boop_db":
fmt = "The bot ran into an error while checking for the boop database information."
await bot.send_message(determineId(ownerID),fmt)'''
cursor.execute('use {0}'.format(db_default))
cursor.execute('use {0}'.format(config.db_default))
cursor.execute('select channel_id from restart_server where id=1')
result = cursor.fetchone()['channel_id']
if int(result) != 0:
await bot.send_message(determineId(result), "I have just finished restarting!")
destination = discord.utils.find(lambda m: m.id == result, bot.get_all_channels())
await bot.send_message(destination, "I have just finished restarting!")
cursor.execute('update restart_server set channel_id=0 where id=1')
connection.commit()
config.connection.commit()
@bot.event
@ -110,540 +41,7 @@ async def on_member_join(member):
async def on_member_remove(member):
await bot.say("{0} has left the server, I hope it wasn't because of something I said :c".format(member))
# Bot commands
@bot.command()
async def joke():
try:
fortuneCommand = "/usr/bin/fortune riddles"
fortune = subprocess.check_output(fortuneCommand.split()).decode("utf-8")
await bot.say(fortune)
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await bot.say(fmt.format(type(e).__name__, e))
@bot.command(pass_context=True)
@isOwner()
async def restart(ctx):
try:
cursor = connection.cursor()
cursor.execute('use {0}'.format(db_default))
sql = "update restart_server set channel_id={0} where id=1".format(ctx.message.channel.id)
cursor.execute(sql)
connection.commit()
await bot.say("Restarting; see you in the next life {0}!".format(ctx.message.author.mention))
python = sys.executable
os.execl(python, python, *sys.argv)
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await bot.say(fmt.format(type(e).__name__, e))
@bot.command(pass_context=True)
@isOwner()
async def py(ctx):
try:
match_single = getter.findall(ctx.message.content)
match_multi = multi.findall(ctx.message.content)
if not match_single and not match_multi:
return
else:
if not match_multi:
result = eval(match_single[0])
await bot.say("```{0}```".format(result))
else:
def r(v):
loop.create_task(bot.say("```{0}```".format(v)))
exec(match_multi[0])
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await bot.say(fmt.format(type(e).__name__, e))
@bot.command(pass_context=True)
@isOwner()
async def shutdown(ctx):
try:
fmt = 'Shutting down, I will miss you {0.author.name}'
await bot.say(fmt.format(ctx.message))
await bot.logout()
await bot.close()
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await bot.say(fmt.format(type(e).__name__, e))
@bot.command()
@isOwner()
async def avatar(content):
try:
file = '/home/phxntx5/public_html/bot/images/' + content
with open(file, 'rb') as fp:
await bot.edit_profile(avatar=fp.read())
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await bot.say(fmt.format(type(e).__name__, e))
@bot.command()
@isOwner()
async def name(newNick):
try:
await bot.edit_profile(username=newNick)
await bot.say('Changed username to ' + newNick)
# Restart the bot after this, as profile changes are not immediate
python = sys.executable
os.execl(python, python, *sys.argv)
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await bot.say(fmt.format(type(e).__name__, e))
@bot.command(pass_context=True, no_pm=True)
@isOwner()
async def leave(ctx):
try:
await bot.say('Why must I leave? Hopefully I can come back :c')
await bot.leave_server(ctx.message.server)
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await bot.say(fmt.format(type(e).__name__, e))
@bot.command()
@isMod()
async def status(*stat: str):
try:
newStatus = ' '.join(stat)
game = discord.Game(name=newStatus, type=0)
await bot.change_status(game)
await bot.say("Just changed my status to '{0}'!".format(newStatus))
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await bot.say(fmt.format(type(e).__name__, e))
@bot.command(pass_context=True)
@isMod()
async def say(ctx, *msg: str):
try:
msg = ' '.join(msg)
await bot.say(msg)
await bot.delete_message(ctx.message)
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await bot.say(fmt.format(type(e).__name__, e))
@bot.command()
async def urban(*msg: str):
try:
term = '+'.join(msg)
url = "http://api.urbandictionary.com/v0/define?term={}".format(term)
response = urllib.request.urlopen(url)
data = json.loads(response.read().decode('utf-8'))
if len(data['list']) == 0:
await bot.say("No result with that term!")
else:
await bot.say(data['list'][0]['definition'])
except discord.HTTPException:
await bot.say('```Error: Defintion is too long for me to send```')
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await bot.say(fmt.format(type(e).__name__, e))
@bot.command(pass_context=True)
async def derpi(ctx, *search: str):
try:
if len(search) > 0:
url = 'https://derpibooru.org/search.json?q='
query = '+'.join(search)
url += query
if ctx.message.channel.id in nsfwChannels:
url += ",+explicit&filter_id=95938"
# url should now be in the form of url?q=search+terms
# Next part processes the json format, and saves the data in useful lists/dictionaries
response = urllib.request.urlopen(url)
data = json.loads(response.read().decode('utf-8'))
results = data['search']
if len(results) > 0:
index = random.randint(0, len(results) - 1)
randImageUrl = results[index].get('representations').get('full')[2:]
randImageUrl = 'http://' + randImageUrl
imageLink = randImageUrl.strip()
else:
await bot.say("No results with that search term, {0}!".format(ctx.message.author.mention))
return
else:
with urllib.request.urlopen('https://derpibooru.org/images/random') as response:
imageLink = response.geturl()
url = 'https://shpro.link/redirect.php/'
data = urllib.parse.urlencode({'link': imageLink}).encode('ascii')
response = urllib.request.urlopen(url, data).read().decode('utf-8')
await bot.say(response)
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await bot.say(fmt.format(type(e).__name__, e))
@bot.command(pass_context=True)
async def roll(ctx):
try:
num = random.randint(1, 6)
fmt = '{0.author.name} has rolled a die and got the number {1}!'
await bot.say(fmt.format(ctx.message, num))
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await bot.say(fmt.format(type(e).__name__, e))
@bot.command(no_pm=True)
@battled()
async def accept():
try:
if not battling:
return
num = random.randint(1, 100)
fmt = battleWins[random.randint(0, len(battleWins) - 1)]
if num <= 50:
await bot.say(fmt.format(battleP1.mention, battleP2.mention))
updateBattleRecords(battleP1, battleP2)
elif num > 50:
await bot.say(fmt.format(battleP2.mention, battleP1.mention))
updateBattleRecords(battleP2, battleP1)
battlingOff()
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await bot.say(fmt.format(type(e).__name__, e))
@bot.command(no_pm=True)
@battled()
async def decline():
try:
if not battling:
return
await bot.say("{0} has chickened out! {1} wins by default!".format(battleP2.mention, battleP1.mention))
updateBattleRecords(battleP1, battleP2)
battlingOff()
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await bot.say(fmt.format(type(e).__name__, e))
@bot.command(pass_context=True)
async def commands(ctx):
try:
fmt = 'Hello {0.author.name}!\n\nThis is {1.user.name}! '
fmt += 'Here is a list of commands that you have access to '
fmt += '(please note that this only includes the commands that you have access to):'
await bot.whisper(fmt.format(ctx.message, bot))
fmt2 = 'I have just sent you a PM, containing all the commands you have access to {0.author.mention}!'
ocmds = 'Commands for everyone: ```'
for com, act in openCommands.items():
ocmds += commandPrefix + com + ": " + act + "\n\n"
ocmds += '```'
await bot.whisper(ocmds)
vcmds = 'Voice Commands: ```'
for com, act in voiceCommands.items():
vcmds += commandPrefix + com + ": " + act + "\n\n"
vcmds += '```'
await bot.whisper(vcmds)
if ctx.message.author.top_role.permissions.kick_members:
if len(modCommands) > 0:
mcmds = 'Moderator Commands: ```'
for com, act in modCommands.items():
mcmds += commandPrefix + com + ": " + act + "\n\n"
mcmds += '```'
await bot.whisper(mcmds)
if ctx.message.author.top_role.permissions.manage_server:
if len(adminCommands) > 0:
acmds = 'Admin Commands: ```'
for com, act in adminCommands.items():
acmds += commandPrefix + com + ": " + act + "\n\n"
acmds += '```'
await bot.whisper(acmds)
if ctx.message.author.id == ownerID:
if len(ownerCommands) > 0:
owncmds = 'Owner Commands: ```'
for com, act in ownerCommands.items():
owncmds += commandPrefix + com + ": " + act + "\n\n"
owncmds += '```'
await bot.whisper(owncmds)
await bot.say(fmt2.format(ctx.message))
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await bot.say(fmt.format(type(e).__name__, e))
@bot.command(pass_context=True, no_pm=True)
async def battle(ctx):
try:
global battleP1
global battleP2
global battling
if battling:
return
if len(ctx.message.mentions) == 0:
await bot.say("You must mention someone in the room " + ctx.message.author.mention + "!")
return
if len(ctx.message.mentions) > 1:
await bot.say("You cannot battle more than one person at once!")
return
player2 = ctx.message.mentions[0]
if ctx.message.author.id == player2.id:
await bot.say("Why would you want to battle yourself? Suicide is not the answer")
return
if bot.user.id == player2.id:
await bot.say("I always win, don't even try it.")
return
fmt = "{0.mention} has challenged you to a battle {1.mention}\n!accept or !decline"
battleP1 = ctx.message.author
battleP2 = player2
await bot.say(fmt.format(ctx.message.author, player2))
t = Timer(180, battlingOff)
t.start()
battling = True
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await bot.say(fmt.format(type(e).__name__, e))
@bot.command(pass_context=True, no_pm=True)
async def boop(ctx):
try:
if len(ctx.message.mentions) == 0:
await bot.say("You must mention someone in the room " + ctx.message.author.mention + "!")
return
if len(ctx.message.mentions) > 1:
await bot.say("You cannot boop more than one person at once!")
return
boopee = ctx.message.mentions[0]
booper = ctx.message.author
if boopee.id == booper.id:
await bot.say("You can't boop yourself! Silly...")
return
if boopee.id == bot.user.id:
await bot.say("Why the heck are you booping me? Get away from me >:c")
return
cursor = connection.cursor()
cursor.execute('use {0}'.format(db_boops))
sql = "show tables like '" + str(booper.id) + "'"
cursor.execute(sql)
result = cursor.fetchone()
amount = 1
# Booper's table exists, continue
if result is not None:
sql = "select `amount` from `" + booper.id + "` where id='" + str(boopee.id) + "'"
cursor.execute(sql)
result = cursor.fetchone()
# Boopee's entry exists, continue
if result is not None:
amount = result.get('amount') + 1
sql = "update `" + str(booper.id) + "` set amount = " + str(amount) + " where id=" + str(
boopee.id)
cursor.execute(sql)
# Boopee does not exist, need to create the field for it
else:
sql = "insert into `" + str(booper.id) + "` (id,amount) values ('" + str(boopee.id) + "',1)"
cursor.execute(sql)
# Booper's table does not exist, need to create the table
else:
sql = "create table `" + str(booper.id) + \
"` (`id` varchar(255) not null,`amount` int(11) not null" + \
",primary key (`id`)) engine=InnoDB default charset=utf8 collate=utf8_bin"
cursor.execute(sql)
sql = "insert into `" + str(booper.id) + "` (id,amount) values ('" + str(boopee.id) + "',1)"
cursor.execute(sql)
fmt = "{0.mention} has just booped you {1.mention}! That's {2} times now!"
await bot.say(fmt.format(booper, boopee, amount))
connection.commit()
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await bot.say(fmt.format(type(e).__name__, e))
@bot.command(pass_context=True, no_pm=True)
async def mostboops(ctx):
try:
cursor = connection.cursor()
cursor.execute('use {0}'.format(db_boops))
sql = "select id,amount from `{0}` where amount=(select MAX(amount) from `{0}`)".format(ctx.message.author.id)
cursor.execute(sql)
result = cursor.fetchone()
member = determineId(result.get('id'))
await bot.say("{0} you have booped {1} the most amount of times, coming in at {2} times".format(
ctx.message.author.mention, member.mention, result.get('amount')))
connection.commit()
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await bot.say(fmt.format(type(e).__name__, e))
@bot.command(pass_context=True, no_pm=True)
async def mostwins(ctx):
try:
members = ctx.message.server.members
cursor = connection.cursor()
cursor.execute('use {0}'.format(db_default))
sql = "select * from battle_records"
cursor.execute(sql)
result = cursor.fetchall()
count = 0
fmt = []
if result is not None:
for r in result:
member = determineId(r['id'])
if member in members:
record = r['record']
winAmt = int(record.split('-')[0])
loseAmt = int(record.split('-')[1])
percentage = winAmt / (winAmt + loseAmt)
position = count
indexPercentage = 0
if count > 0:
indexRecord = re.search('\d+-\d+', fmt[position - 1]).group(0)
indexWin = int(indexRecord.split('-')[0])
indexLose = int(indexRecord.split('-')[1])
indexPercentage = indexWin / (indexWin + indexLose)
while position > 0 and indexPercentage < percentage:
position -= 1
indexRecord = re.search('\d+-\d+', fmt[position - 1]).group(0)
indexWin = int(indexRecord.split('-')[0])
indexLose = int(indexRecord.split('-')[1])
indexPercentage = indexWin / (indexWin + indexLose)
fmt.insert(position, "{0} has a battling record of {1}".format(member.name, record))
count += 1
for index in range(0, len(fmt)):
fmt[index] = "{0}) {1}".format(index + 1, fmt[index])
connection.commit()
if len(fmt) == 0:
await bot.say("```No battling records found from any members in this server```")
return
await bot.say("```{}```".format("\n".join(fmt)))
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await bot.say(fmt.format(type(e).__name__, e))
def determineId(ID):
if type(ID) is int:
ID = str(ID)
member = discord.utils.find(lambda m: m.id == ID, bot.get_all_members())
if member is not None:
return member
msg = discord.utils.find(lambda m: m.id == ID, bot.messages)
if msg is not None:
return msg
server = discord.utils.find(lambda s: s.id == ID, bot.servers)
if server is not None:
return server
channel = discord.utils.find(lambda c: c.id == ID, bot.get_all_channels())
if channel is not None:
return channel
def updateBattleRecords(winner, loser):
cursor = connection.cursor()
cursor.execute('use {0}'.format(db_default))
# Update winners records
sql = "select record from battle_records where id={0}".format(winner.id)
cursor.execute(sql)
result = cursor.fetchone()
if result is not None:
result = result['record'].split('-')
result[0] = str(int(result[0]) + 1)
sql = "update battle_records set record ='{0}' where id='{1}'".format("-".join(result), winner.id)
cursor.execute(sql)
else:
sql = "insert into battle_records (id,record) values ('{0}','1-0')".format(winner.id)
cursor.execute(sql)
connection.commit()
# Update losers records
sql = "select record from battle_records where id={0}".format(loser.id)
cursor.execute(sql)
result = cursor.fetchone()
if result is not None:
result = result['record'].split('-')
result[1] = str(int(result[1]) + 1)
sql = "update battle_records set record ='{0}' where id='{1}'".format('-'.join(result), loser.id)
cursor.execute(sql)
else:
sql = "insert into battle_records (id,record) values ('{0}','0-1')".format(loser.id)
cursor.execute(sql)
connection.commit()
def checkSetup(cursor):
try:
cursor.execute('use {}'.format(db_default))
except pymysql.OperationalError:
return "Error: default_db"
else:
try:
cursor.execute('describe battle_records')
except pymysql.ProgrammingError:
# battle_records does not exist, create it
sql = "create table `battle_records` (`id` varchar(32) not null,`record` varchar(32) not null," + \
"primary key (`id`)) engine=InnoDB default charset=utf8 collate=utf8_bin"
cursor.execute(sql)
connection.commit()
try:
cursor.execute('describe restart_server')
except pymysql.ProgrammingError:
# restart_server does not exist, create it
sql = "create table `restart_server` (`id` int(11) not null auto_increment,`channel_id` varchar(32)" + \
"not null,primary key (`id`)) engine=InnoDB default charset=utf8 collate=utf8_bin;"
cursor.execute(sql)
connection.commit()
sql = "insert into restart_server (id,channel_id) values (1,'0')"
cursor.execute(sql)
connection.commit()
try:
cursor.execute('use {}'.format(db_boops))
except pymysql.OperationalError:
return "Error: boop_db"
db_default = global_config.get("db_default")
db_boops = global_config.get("db_boops")
nsfwChannels = global_config.get("nsfw_channel")
connection = pymysql.connect(host=global_config.get("db_host"), user=global_config.get("db_user"),
password=global_config.get("db_user_pass"), charset='utf8mb4',
cursorclass=pymysql.cursors.DictCursor)
battling = False
battleP1 = None
battleP2 = None
battleWins = global_config.get("battleWins", [])
defaultStatus = global_config.get("default_status", "")
botToken = global_config.get("bot_token", "")
ownerID = global_config.get("owner_id", "")
modCommands = global_config.get("modCommands", {})
adminCommands = global_config.get("adminCommands", {})
openCommands = global_config.get("openCommands", {})
ownerCommands = global_config.get("ownerCommands", {})
voiceCommands = global_config.get("voiceCommands", {})
getter = re.compile(r'`(?!`)(.*?)`')
multi = re.compile(r'```(.*?)```', re.DOTALL)
loop = asyncio.get_event_loop()
try:
bot.run(botToken)
except:
quit()
if __name__ == '__main__':
for e in extensions:
bot.load_extension(e)
bot.run(config.botToken)

92
cogs/core.py Normal file
View file

@ -0,0 +1,92 @@
from discord.ext import commands
from .utils import config
import discord
import subprocess
import urllib.parse
import urllib.request
import json
import random
class Core:
def __init__(self, bot):
self.bot = bot
@commands.command()
async def joke(self):
"""Prints a random riddle"""
try:
fortuneCommand = "/usr/bin/fortune riddles"
fortune = subprocess.check_output(fortuneCommand.split()).decode("utf-8")
await self.bot.say(fortune)
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await self.bot.say(fmt.format(type(e).__name__, e))
@commands.command()
async def urban(self, *msg: str):
"""Pulls the top urbandictionary.com definition for a term"""
try:
term = '+'.join(msg)
url = "http://api.urbandictionary.com/v0/define?term={}".format(term)
response = urllib.request.urlopen(url)
data = json.loads(response.read().decode('utf-8'))
if len(data['list']) == 0:
await self.bot.say("No result with that term!")
else:
await self.bot.say(data['list'][0]['definition'])
except discord.HTTPException:
await self.bot.say('```Error: Definition is too long for me to send```')
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await self.bot.say(fmt.format(type(e).__name__, e))
@commands.command(pass_context=True)
async def derpi(self, ctx, *search: str):
"""Provides a random image from the first page of derpibooru.org for the following term"""
try:
if len(search) > 0:
url = 'https://derpibooru.org/search.json?q='
query = '+'.join(search)
url += query
if ctx.message.channel.id in config.nsfwChannels:
url += ",+explicit&filter_id=95938"
# url should now be in the form of url?q=search+terms
# Next part processes the json format, and saves the data in useful lists/dictionaries
response = urllib.request.urlopen(url)
data = json.loads(response.read().decode('utf-8'))
results = data['search']
if len(results) > 0:
index = random.randint(0, len(results) - 1)
randImageUrl = results[index].get('representations').get('full')[2:]
randImageUrl = 'http://' + randImageUrl
imageLink = randImageUrl.strip()
else:
await self.bot.say("No results with that search term, {0}!".format(ctx.message.author.mention))
return
else:
with urllib.request.urlopen('https://derpibooru.org/images/random') as response:
imageLink = response.geturl()
url = 'https://shpro.link/redirect.php/'
data = urllib.parse.urlencode({'link': imageLink}).encode('ascii')
response = urllib.request.urlopen(url, data).read().decode('utf-8')
await self.bot.say(response)
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await self.bot.say(fmt.format(type(e).__name__, e))
@commands.command(pass_context=True)
async def roll(self, ctx):
"""Rolls a six sided die"""
try:
num = random.randint(1, 6)
fmt = '{0.message.author.name} has rolled a die and got the number {1}!'
await self.bot.say(fmt.format(ctx, num))
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await self.bot.say(fmt.format(type(e).__name__, e))
def setup(bot):
bot.add_cog(Core(bot))

184
cogs/interaction.py Normal file
View file

@ -0,0 +1,184 @@
from discord.ext import commands
from .utils import checks
from .utils import config
from threading import Timer
import random
battling = False
battleP1 = None
battleP2 = None
def battlingOff():
global battleP1
global battleP2
global battling
battling = False
battleP1 = ""
battleP2 = ""
def updateBattleRecords(winner, loser):
cursor = config.connection.cursor()
cursor.execute('use {0}'.format(config.db_default))
# Update winners records
sql = "select record from battle_records where id={0}".format(winner.id)
cursor.execute(sql)
result = cursor.fetchone()
if result is not None:
result = result['record'].split('-')
result[0] = str(int(result[0]) + 1)
sql = "update battle_records set record ='{0}' where id='{1}'".format("-".join(result), winner.id)
cursor.execute(sql)
else:
sql = "insert into battle_records (id,record) values ('{0}','1-0')".format(winner.id)
cursor.execute(sql)
config.connection.commit()
# Update losers records
sql = "select record from battle_records where id={0}".format(loser.id)
cursor.execute(sql)
result = cursor.fetchone()
if result is not None:
result = result['record'].split('-')
result[1] = str(int(result[1]) + 1)
sql = "update battle_records set record ='{0}' where id='{1}'".format('-'.join(result), loser.id)
cursor.execute(sql)
else:
sql = "insert into battle_records (id,record) values ('{0}','0-1')".format(loser.id)
cursor.execute(sql)
config.connection.commit()
class Interaction:
def __init__(self, bot):
self.bot = bot
@commands.command(pass_context=True, no_pm=True)
async def battle(self, ctx):
"""Challenges the mentioned user to a battle"""
try:
global battleP1
global battleP2
global battling
if battling:
return
if len(ctx.message.mentions) == 0:
await self.bot.say("You must mention someone in the room " + ctx.message.author.mention + "!")
return
if len(ctx.message.mentions) > 1:
await self.bot.say("You cannot battle more than one person at once!")
return
player2 = ctx.message.mentions[0]
if ctx.message.author.id == player2.id:
await self.bot.say("Why would you want to battle yourself? Suicide is not the answer")
return
if self.bot.user.id == player2.id:
await self.bot.say("I always win, don't even try it.")
return
fmt = "{0.mention} has challenged you to a battle {1.mention}\n!accept or !decline"
battleP1 = ctx.message.author
battleP2 = player2
await self.bot.say(fmt.format(ctx.message.author, player2))
t = Timer(180, battlingOff)
t.start()
battling = True
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await self.bot.say(fmt.format(type(e).__name__, e))
@commands.command(no_pm=True)
@checks.battled(battleP2)
async def accept(self):
"""Accepts the battle challenge"""
try:
if not battling:
return
num = random.randint(1, 100)
fmt = config.battleWins[random.randint(0, len(config.battleWins) - 1)]
if num <= 50:
await self.bot.say(fmt.format(battleP1.mention, battleP2.mention))
updateBattleRecords(battleP1, battleP2)
elif num > 50:
await self.bot.say(fmt.format(battleP2.mention, battleP1.mention))
updateBattleRecords(battleP2, battleP1)
battlingOff()
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await self.bot.say(fmt.format(type(e).__name__, e))
@commands.command(no_pm=True)
@checks.battled(battleP2)
async def decline(self):
"""Declines the battle challenge"""
try:
if not battling:
return
await self.bot.say("{0} has chickened out! {1} wins by default!".format(battleP2.mention, battleP1.mention))
updateBattleRecords(battleP1, battleP2)
battlingOff()
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await self.bot.say(fmt.format(type(e).__name__, e))
@commands.command(pass_context=True, no_pm=True)
async def boop(self, ctx):
"""Boops the mentioned person"""
try:
if len(ctx.message.mentions) == 0:
await self.bot.say("You must mention someone in the room " + ctx.message.author.mention + "!")
return
if len(ctx.message.mentions) > 1:
await self.bot.say("You cannot boop more than one person at once!")
return
boopee = ctx.message.mentions[0]
booper = ctx.message.author
if boopee.id == booper.id:
await self.bot.say("You can't boop yourself! Silly...")
return
if boopee.id == self.bot.user.id:
await self.bot.say("Why the heck are you booping me? Get away from me >:c")
return
cursor = config.connection.cursor()
cursor.execute('use {0}'.format(config.db_boops))
sql = "show tables like '" + str(booper.id) + "'"
cursor.execute(sql)
result = cursor.fetchone()
amount = 1
# Booper's table exists, continue
if result is not None:
sql = "select `amount` from `" + booper.id + "` where id='" + str(boopee.id) + "'"
cursor.execute(sql)
result = cursor.fetchone()
# Boopee's entry exists, continue
if result is not None:
amount = result.get('amount') + 1
sql = "update `" + str(booper.id) + "` set amount = " + str(amount) + " where id=" + str(
boopee.id)
cursor.execute(sql)
# Boopee does not exist, need to create the field for it
else:
sql = "insert into `" + str(booper.id) + "` (id,amount) values ('" + str(boopee.id) + "',1)"
cursor.execute(sql)
# Booper's table does not exist, need to create the table
else:
sql = "create table `" + str(booper.id) + \
"` (`id` varchar(255) not null,`amount` int(11) not null" + \
",primary key (`id`)) engine=InnoDB default charset=utf8 collate=utf8_bin"
cursor.execute(sql)
sql = "insert into `" + str(booper.id) + "` (id,amount) values ('" + str(boopee.id) + "',1)"
cursor.execute(sql)
fmt = "{0.mention} has just booped you {1.mention}! That's {2} times now!"
await self.bot.say(fmt.format(booper, boopee, amount))
config.connection.commit()
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await self.bot.say(fmt.format(type(e).__name__, e))
def setup(bot):
bot.add_cog(Interaction(bot))

30
cogs/mod.py Normal file
View file

@ -0,0 +1,30 @@
from discord.ext import commands
from .utils import checks
class Mod:
def __init__(self, bot):
self.bot = bot
@commands.command(pass_context=True, no_pm=True)
@checks.isAdmin()
async def leave(self, ctx):
"""Forces the bot to leave the server"""
try:
await self.bot.say('Why must I leave? Hopefully I can come back :c')
await self.bot.leave_server(ctx.message.server)
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await self.bot.say(fmt.format(type(e).__name__, e))
@commands.command(pass_context=True)
@checks.isMod()
async def say(self, ctx, *msg: str):
"""Tells the bot to repeat what you say"""
try:
msg = ' '.join(msg)
await self.bot.say(msg)
await self.bot.delete_message(ctx.message)
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await self.bot.say(fmt.format(type(e).__name__, e))

110
cogs/owner.py Normal file
View file

@ -0,0 +1,110 @@
from discord.ext import commands
from .utils import config
from .utils import checks
import re
import os
import sys
import discord
getter = re.compile(r'`(?!`)(.*?)`')
multi = re.compile(r'```(.*?)```', re.DOTALL)
class Owner:
def __init__(self, bot):
self.bot = bot
@commands.command(pass_context=True)
@checks.isOwner()
async def restart(self, ctx):
"""Forces the bot to restart"""
try:
cursor = config.connection.cursor()
cursor.execute('use {0}'.format(config.db_default))
sql = "update restart_server set channel_id={0} where id=1".format(ctx.message.channel.id)
cursor.execute(sql)
config.connection.commit()
await self.bot.say("Restarting; see you in the next life {0}!".format(ctx.message.author.mention))
python = sys.executable
os.execl(python, python, *sys.argv)
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await self.bot.say(fmt.format(type(e).__name__, e))
@commands.command(pass_context=True)
@checks.isOwner()
async def py(self, ctx):
"""Executes code"""
try:
match_single = getter.findall(ctx.message.content)
match_multi = multi.findall(ctx.message.content)
if not match_single and not match_multi:
return
else:
if not match_multi:
result = eval(match_single[0])
await self.bot.say("```{0}```".format(result))
else:
def r(v):
config.loop.create_task(self.bot.say("```{0}```".format(v)))
exec(match_multi[0])
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await self.bot.say(fmt.format(type(e).__name__, e))
@commands.command(pass_context=True)
@checks.isOwner()
async def shutdown(self, ctx):
"""Shuts the bot down"""
try:
fmt = 'Shutting down, I will miss you {0.author.name}'
await self.bot.say(fmt.format(ctx.message))
await self.bot.logout()
await self.bot.close()
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await self.bot.say(fmt.format(type(e).__name__, e))
@commands.command()
@checks.isOwner()
async def avatar(self, content):
"""Changes the avatar for the bot to the filename following the command"""
try:
file = '/home/phxntx5/public_html/bot/images/' + content
with open(file, 'rb') as fp:
await self.bot.edit_profile(avatar=fp.read())
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await self.bot.say(fmt.format(type(e).__name__, e))
@commands.command()
@checks.isOwner()
async def name(self, newNick):
"""Changes the bot's name"""
try:
await self.bot.edit_profile(username=newNick)
await self.bot.say('Changed username to ' + newNick)
# Restart the bot after this, as profile changes are not immediate
python = sys.executable
os.execl(python, python, *sys.argv)
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await self.bot.say(fmt.format(type(e).__name__, e))
@commands.command()
@checks.isOwner()
async def status(self, *stat: str):
"""Changes the bot's 'playing' status"""
try:
newStatus = ' '.join(stat)
game = discord.Game(name=newStatus, type=0)
await self.bot.change_status(game)
await self.bot.say("Just changed my status to '{0}'!".format(newStatus))
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await self.bot.say(fmt.format(type(e).__name__, e))
def setup(bot):
bot.add_cog(Owner(bot))

View file

@ -2,10 +2,12 @@ import asyncio
import discord
import traceback
from discord.ext import commands
from .utils import checks
if not discord.opus.is_loaded():
discord.opus.load_opus('/usr/lib64/libopus.so.0')
class VoiceEntry:
def __init__(self, message, player):
self.requester = message.author
@ -16,9 +18,10 @@ class VoiceEntry:
fmt = '*{0.title}* uploaded by {0.uploader} and requested by {1.display_name}'
duration = self.player.duration
if duration:
fmt += ' [length: {0[0]}m {0[1]}s]'.format(divmod(round(duration,0), 60))
fmt += ' [length: {0[0]}m {0[1]}s]'.format(divmod(round(duration, 0), 60))
return fmt.format(self.player, self.requester)
class VoiceState:
def __init__(self, bot):
self.current = None
@ -26,7 +29,7 @@ class VoiceState:
self.bot = bot
self.play_next_song = asyncio.Event()
self.songs = asyncio.Queue()
self.skip_votes = set() # a set of user_ids that voted
self.skip_votes = set() # a set of user_ids that voted
self.audio_player = self.bot.loop.create_task(self.audio_player_task())
def is_playing(self):
@ -56,6 +59,7 @@ class VoiceState:
self.current.player.start()
await self.play_next_song.wait()
class Music:
"""Voice related commands.
Works in multiple servers at once.
@ -85,13 +89,9 @@ class Music:
self.bot.loop.create_task(state.voice.disconnect())
except:
pass
def isMod():
def predicate(ctx):
return ctx.message.author.top_role.permissions.kick_members
return commands.check(predicate)
@commands.command(pass_context=True, no_pm=True)
async def join(self, ctx, *, channel : discord.Channel):
@commands.command(no_pm=True)
async def join(self, *, channel: discord.Channel):
"""Joins a voice channel."""
try:
await self.create_voice_client(channel)
@ -121,7 +121,7 @@ class Music:
return True
@commands.command(pass_context=True, no_pm=True)
async def play(self, ctx, *, song : str):
async def play(self, ctx, *, song: str):
"""Plays a song.
If there is a song currently in the queue, then it is
queued until the next song is done playing.
@ -147,8 +147,8 @@ class Music:
await state.songs.put(entry)
@commands.command(pass_context=True, no_pm=True)
@isMod()
async def volume(self, ctx, value : int):
@checks.isMod()
async def volume(self, ctx, value: int):
"""Sets the volume of the currently playing song."""
state = self.get_voice_state(ctx.message.server)
@ -158,7 +158,7 @@ class Music:
await self.bot.say('Set the volume to {:.0%}'.format(player.volume))
@commands.command(pass_context=True, no_pm=True)
@isMod()
@checks.isMod()
async def pause(self, ctx):
"""Pauses the currently played song."""
state = self.get_voice_state(ctx.message.server)
@ -167,7 +167,7 @@ class Music:
player.pause()
@commands.command(pass_context=True, no_pm=True)
@isMod()
@checks.isMod()
async def resume(self, ctx):
"""Resumes the currently played song."""
state = self.get_voice_state(ctx.message.server)
@ -176,7 +176,7 @@ class Music:
player.resume()
@commands.command(pass_context=True, no_pm=True)
@isMod()
@checks.isMod()
async def stop(self, ctx):
"""Stops playing audio and leaves the voice channel.
This also clears the queue.
@ -194,11 +194,13 @@ class Music:
await state.voice.disconnect()
except:
pass
@commands.command(pass_context=True,no_pm=True)
async def queuelength(self,ctx):
@commands.command(pass_context=True, no_pm=True)
async def queuelength(self, ctx):
"""Prints the length of the queue"""
try:
await self.bot.say("There are a total of {} songs in the queue".format(str(self.get_voice_state(ctx.message.server).songs.qsize())))
await self.bot.say("There are a total of {} songs in the queue"
.format(str(self.get_voice_state(ctx.message.server).songs.qsize())))
except:
await self.bot.say(traceback.format_exc())
@ -229,7 +231,7 @@ class Music:
await self.bot.say('You have already voted to skip this song.')
@commands.command(pass_context=True, no_pm=True)
@isMod()
@checks.isMod()
async def modskip(self, ctx):
"""Forces a song skip, can only be used by a moderator"""
state = self.get_voice_state(ctx.message.server)
@ -250,3 +252,7 @@ class Music:
else:
skip_count = len(state.skip_votes)
await self.bot.say('Now playing {} [skips: {}/3]'.format(state.current, skip_count))
def setup(bot):
bot.add_cog(Music(bot))

80
cogs/stats.py Normal file
View file

@ -0,0 +1,80 @@
from discord.ext import commands
from discord.utils import find
from .utils import config
import re
class Stats:
def __init__(self, bot):
self.bot = bot
@commands.command(pass_context=True, no_pm=True)
async def mostboops(self, ctx):
"""Shows the person you have 'booped' the most, as well as how many times"""
try:
cursor = config.connection.cursor()
cursor.execute('use {0}'.format(config.db_boops))
sql = "select id,amount from `{0}` where amount=(select MAX(amount) from `{0}`)"\
.format(ctx.message.author.id)
cursor.execute(sql)
result = cursor.fetchone()
member = find(lambda m: m.id == result.get('id'), self.bot.get_all_members())
await self.bot.say("{0} you have booped {1} the most amount of times, coming in at {2} times".format(
ctx.message.author.mention, member.mention, result.get('amount')))
config.connection.commit()
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await self.bot.say(fmt.format(type(e).__name__, e))
@commands.command(pass_context=True, no_pm=True)
async def mostwins(self, ctx):
"""Prints a 'leaderboard' of everyone in the server's battling record"""
try:
members = ctx.message.server.members
cursor = config.connection.cursor()
cursor.execute('use {0}'.format(config.db_default))
sql = "select * from battle_records"
cursor.execute(sql)
result = cursor.fetchall()
count = 0
fmt = []
if result is not None:
for r in result:
member = self.bot.determineId(r['id'])
if member in members:
record = r['record']
winAmt = int(record.split('-')[0])
loseAmt = int(record.split('-')[1])
percentage = winAmt / (winAmt + loseAmt)
position = count
indexPercentage = 0
if count > 0:
indexRecord = re.search('\d+-\d+', fmt[position - 1]).group(0)
indexWin = int(indexRecord.split('-')[0])
indexLose = int(indexRecord.split('-')[1])
indexPercentage = indexWin / (indexWin + indexLose)
while position > 0 and indexPercentage < percentage:
position -= 1
indexRecord = re.search('\d+-\d+', fmt[position - 1]).group(0)
indexWin = int(indexRecord.split('-')[0])
indexLose = int(indexRecord.split('-')[1])
indexPercentage = indexWin / (indexWin + indexLose)
fmt.insert(position, "{0} has a battling record of {1}".format(member.name, record))
count += 1
for index in range(0, len(fmt)):
fmt[index] = "{0}) {1}".format(index + 1, fmt[index])
config.connection.commit()
if len(fmt) == 0:
await self.bot.say("```No battling records found from any members in this server```")
return
await self.bot.say("```{}```".format("\n".join(fmt)))
except Exception as e:
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
await self.bot.say(fmt.format(type(e).__name__, e))
def setup(bot):
bot.add_cog(Stats(bot))

37
cogs/utils/checks.py Normal file
View file

@ -0,0 +1,37 @@
from discord.ext import commands
from . import config
def isOwner():
def predicate(ctx):
return ctx.message.author.id == config.ownerID
return commands.check(predicate)
def isMod():
def predicate(ctx):
return ctx.message.author.top_role.permissions.kick_members
return commands.check(predicate)
def isAdmin():
def predicate(ctx):
return ctx.message.author.top_role.permissions.manage_server
return commands.check(predicate)
def isPM():
def predicate(ctx):
return ctx.message.channel.is_private
return commands.check(predicate)
def battled(battleP2=""):
def predicate(ctx):
return ctx.message.author == battleP2
return commands.check(predicate)

29
cogs/utils/config.py Normal file
View file

@ -0,0 +1,29 @@
import yaml
import pymysql.cursors
import asyncio
loop = asyncio.get_event_loop()
with open("/home/phxntx5/public_html/Bonfire/config.yml", "r") as f:
global_config = yaml.load(f)
db_default = global_config.get("db_default")
db_boops = global_config.get("db_boops")
nsfwChannels = global_config.get("nsfw_channel")
connection = pymysql.connect(host=global_config.get("db_host"), user=global_config.get("db_user"),
password=global_config.get("db_user_pass"), charset='utf8mb4',
cursorclass=pymysql.cursors.DictCursor)
botDescription = global_config.get("description")
commandPrefix = global_config.get("command_prefix")
battleWins = global_config.get("battleWins", [])
defaultStatus = global_config.get("default_status", "")
botToken = global_config.get("bot_token", "")
ownerID = global_config.get("owner_id", "")
modCommands = global_config.get("modCommands", {})
adminCommands = global_config.get("adminCommands", {})
openCommands = global_config.get("openCommands", {})
ownerCommands = global_config.get("ownerCommands", {})
voiceCommands = global_config.get("voiceCommands", {})