discordbot/bot.py

783 lines
41 KiB
Python

#!/usr/bin/env python3
import discord
from discord.ext import commands, tasks
from discord.utils import get
from sqlite3 import connect
from datetime import datetime
from config import *
from requests import get
from json import loads
from os import remove, listdir
from youtube_dlc import YoutubeDL
from time import time
from asyncio import sleep
from io import BytesIO
from hangman import *
polls = {}
hangmanMessages = {}
player = None # the Player for the music Bot
playerServer = None # The Server the player is active at the moment
audioPlayer = None
playerQue = []
titleQue = []
fileIndex = 0
playing = False
bot = commands.Bot(command_prefix=prefix)
dbconnection = connect('database.db')
dbcursor = dbconnection.cursor()
sql = "CREATE TABLE IF NOT EXISTS MESSAGES(id INTEGER PRIMARY KEY DEFAULT NULL, LONG, server LONG, textXP LONG, reactionXP LONG, vcXP LONG)"
sql2 = "CREATE TABLE IF NOT EXISTS VcActive (id INTEGER PRIMARY KEY DEFAULT NULL, user LONG, startTime LONG)"
sql3 = "CREATE TABLE IF NOT EXISTS poll (id INTEGER PRIMARY KEY DEFAULT NULL, pollID LONG, reaction STRING, calls LONG)"
sql4 = "CREATE TABLE IF NOT EXISTS hangman (id INTEGER PRIMARY KEY DEFAULT NULL, gameID LONG, channel LONG, owner LONG, word STRING, right STRING, wrong STRING)"
dbcursor.execute(sql)
dbcursor.execute(sql2)
dbcursor.execute(sql3)
dbcursor.execute(sql4)
@bot.event # print the username and id to the console and change the game status
async def on_ready():
print('Logged in as')
print(bot.user.name)
print(bot.user.id)
print('------')
if activity == 0:
await bot.change_presence(activity=discord.Game(name=name, start=datetime.fromtimestamp(gameStartTime)))
if activity == 1:
await bot.change_presence(activity=discord.Streaming(name=name, url=url))
if activity == 2:
await bot.change_presence(activity=discord.Activity(type=discord.ActivityType.listening, name=name))
if activity == 3:
await bot.change_presence(activity=discord.Activity(type=discord.ActivityType.watching, name=name))
#
#
# _ __ ___ __ __ _ __ ___ ___ ___ ___ __ _ __ _ ___
# | '_ \ / _ \\ \ /\ / / | '_ ` _ \ / _ \/ __|/ __| / _` | / _` | / _ \
# | | | || __/ \ V V / | | | | | || __/\__ \\__ \| (_| || (_| || __/
# |_| |_| \___| \_/\_/ |_| |_| |_| \___||___/|___/ \__,_| \__, | \___|
# __/ |
# |___/
@bot.event
async def on_message(message): # this will run on every message
global hangmanMessages
if (message.guild == None):
result = dbcursor.execute("SELECT * FROM hangman WHERE owner=? ORDER BY id DESC", [str(message.author.id)]).fetchone()
if result == None:
return
if(result[4] == ""):
dbcursor.execute("UPDATE hangman SET word=? where id=?", [message.content.lower(), result[0]])
dbconnection.commit()
await hangmanMessages[str(result[1])].delete()
hangmanMessages[str(result[1])] = await bot.get_channel(result[2]).send(generateHangmanMessage(message.content.lower(), "", ""))
if "time" in message.content: # this is for fun, if the user sends the bot private a message with time in it, send him the current time
current_time = datetime.now().strftime("%H:%M:%S") # get the time as string
await message.author.send("Current time: " + current_time) # send the current time to the user as DM
return # don't execute the rest (will fail in the next step)
elif(len(message.content) == 1):
result = dbcursor.execute("SELECT * FROM hangman WHERE channel=? ORDER BY id DESC", [str(message.channel.id)]).fetchone()
if(result != None):
word = result[4]
right = result[5]
wrong = result[6]
if message.content.lower() in word and not (message.content.lower() in right):
if(right != ""):
right = right + ";" + message.content
else:
right = message.content.lower()
elif not (message.content.lower() in word) and not (message.content.lower() in wrong):
if (wrong != ""):
wrong = wrong + ";" + message.content.lower()
else:
wrong = message.content.lower()
dbcursor.execute("UPDATE hangman SET wrong=?, right=? WHERE id=?", [wrong, right, result[0]])
dbconnection.commit()
await hangmanMessages[str(result[1])].edit(content=generateHangmanMessage(word, right, wrong))
wordTemp = word
for letters in right.split(";"):
wordTemp = wordTemp.replace(letters, "")
for letters in list(wordTemp):
if not letters in "abcdefghijklmnopqrstuvwxyz":
wordTemp = wordTemp.replace(letters, "")
print(len(wrong.split(";")))
if(wordTemp == ""):
await hangmanMessages[str(result[1])].edit(content=generateHangmanMessage(word, right, wrong) + "\n\ngame finished")
dbcursor.execute("DELETE FROM hangman WHERE id=?", [result[0]])
dbconnection.commit()
elif(len(wrong.split(";")) >= 11):
await hangmanMessages[str(result[1])].edit(content=generateHangmanMessage(word, right, wrong) + "\n\ngame lost. The right word was `" + word + "`")
dbcursor.execute("DELETE FROM hangman WHERE id=?", [result[0]])
dbconnection.commit()
try:
if (len(
allowOnServer) > 0) and message.guild.id not in allowOnServer: # check if whitelist is enabled and Server on list
return # don't execute the rest
except:
pass
print(
str(message.author) + " sent: " + str(message.content) + ", latency: " + str(bot.latency) + " ms, Bot: " + str(
message.author.bot)) # print some information about the message to the console
if message.author.bot or (
message.author.id == bot.user.id): # check if the bot has written the message, if yes stop parsing it
return
try:
res = dbcursor.execute("SELECT textXP FROM MESSAGES WHERE user=? AND server = ?",
[message.author.id, message.guild.id]) # try to get the current textXP of the user
result = res.fetchone()
if result == None:
dbcursor.execute("INSERT INTO MESSAGES VALUES (?, ?, ?, 0, 0)", [message.author.id, message.guild.id,
messageXP]) # if Bot can't find the user in the Database create a new entry
else:
messages = result[0] + messageXP
dbcursor.execute("UPDATE MESSAGES SET textXP = ? WHERE user = ? AND server = ?",
[messages, message.author.id, message.guild.id]) # update the textXP value in the Database
except:
pass
dbconnection.commit() # write the database changes to disk
if message.content.startswith(prefix): # check if the message starts with the prefix, if yes process the command
await bot.process_commands(message)
if "<@!" + str(bot.user.id) + ">" in message.content:
if (message.content[:3] == "hi ") or (message.content[-3:] == " hi"):
await message.channel.send(
"Hello <@!" + str(message.author.id) + "> To get a list of my commands enter " + prefix + "help.")
# _ _ _ _
# | | (_) | | | |
# _ __ ___ __ _ ___ | |_ _ ___ _ __ __ _ __| | __| |
# | '__| / _ \ / _` | / __|| __|| | / _ \ | '_ \ / _` | / _` | / _` |
# | | | __/| (_| || (__ | |_ | || (_) || | | | | (_| || (_| || (_| |
# |_| \___| \__,_| \___| \__||_| \___/ |_| |_| \__,_| \__,_| \__,_|
#
#
@bot.event
async def on_raw_reaction_add(message): # this runs on every reaction
if (message.user_id == bot.user.id): # check if the bot has written the message, if yes stop parsing it
return
res = dbcursor.execute("SELECT reactionXP FROM MESSAGES WHERE user=? AND server = ?",
[message.user_id, message.guild_id]) # try to get the reactionXP from the database
result = res.fetchone()
if (result == None):
dbcursor.execute("INSERT INTO MESSAGES VALUES (?, ?, 0, ?, 0)", [message.user_id, message.guild_id,
reactionXP]) # if bot can't find the database entry for the user create a new one
messages = reactionXP
else:
messages = result[0] + reactionXP
dbcursor.execute("UPDATE MESSAGES SET reactionXP = ? WHERE user = ? AND server = ?",
[messages, message.user_id, message.guild_id]) # update the reactionXP with the new values
try:
polls[str(message.message_id)][0] # check if the reaction is on a poll
calls = dbcursor.execute("SELECT calls FROM poll WHERE pollID = ? AND reaction = ?",
[message.message_id, str(message.emoji)]).fetchone()[
0] # if yes update the database and add 1 vote
dbcursor.execute("UPDATE poll SET calls = ? WHERE pollID = ? AND reaction = ?",
[calls + 1, message.message_id, str(message.emoji)])
except:
pass
dbconnection.commit() # write the database changes to disk
# _ _
# | | (_)
# _ __ ___ __ _ ___ | |_ _ ___ _ __ _ __ ___ _ __ ___ ___ __ __ ___
# | '__| / _ \ / _` | / __|| __|| | / _ \ | '_ \ | '__| / _ \| '_ ` _ \ / _ \ \ \ / / / _ \
# | | | __/| (_| || (__ | |_ | || (_) || | | | | | | __/| | | | | || (_) | \ V / | __/
# |_| \___| \__,_| \___| \__||_| \___/ |_| |_| |_| \___||_| |_| |_| \___/ \_/ \___|
#
#
@bot.event
async def on_raw_reaction_remove(message):
try:
polls[str(message.message_id)][0] # check if the message is a poll
calls = dbcursor.execute("SELECT calls FROM poll WHERE pollID = ? AND reaction = ?",
[message.message_id, str(message.emoji)]).fetchone()[
0] # if yes update the database and remove 1 vote
dbcursor.execute("UPDATE poll SET calls = ? WHERE pollID = ? AND reaction = ?",
[calls - 1, message.message_id, str(message.emoji)])
except:
pass
dbconnection.commit() # write the database changes to disk
# _ _ _ _ _
# (_) | | | | | | | |
# __ __ ___ _ ___ ___ ___ | |__ __ _ | |_ _ _ _ __ __| | __ _ | |_ ___
# \ \ / / / _ \ | | / __| / _ \ / __|| '_ \ / _` || __| | | | || '_ \ / _` | / _` || __| / _ \
# \ V / | (_) || || (__ | __/| (__ | | | || (_| || |_ | |_| || |_) || (_| || (_| || |_ | __/
# \_/ \___/ |_| \___| \___| \___||_| |_| \__,_| \__| \__,_|| .__/ \__,_| \__,_| \__| \___|
# | |
# |_|
@bot.event
async def on_voice_state_update(member, before,
after): # this runs on every voice chat update (user joins, leaves, go afk, moves, ...)
if member.bot or (member.id == bot.user.id): # check if the bot is the user, if yes stop parsing it
return
if not before.afk and after.afk: # check if the user moved from not afk to afk
print(str(member) + " is now AFK")
result = dbcursor.execute("SELECT startTime FROM VcActive WHERE user=?", [member.id]).fetchone()[
0] # if yes, get the join time from the database
dbcursor.execute("DELETE FROM VcActive WHERE user=?",
[member.id]) # delete the entries from the voicechat in the database
xp = (time() - result) / minutesPerVcXP # calculate the xp
result = dbcursor.execute("SELECT vcXP FROM MESSAGES WHERE user=? AND server = ?",
[member.id, member.guild.id]).fetchone()[
0] # update the user database and set the new Voice XP
dbcursor.execute("UPDATE MESSAGES SET vcXP = ? WHERE user = ? AND server = ?",
[result + round(xp), member.id, member.guild.id])
dbconnection.commit() # write the changes to the database
return
if before.afk and not after.afk: # check if the user moved from afk back to active
print(str(member) + " is active again")
dbcursor.execute("INSERT INTO VcActive VALUES (?, ?)",
[member.id, round(time())]) # insert the current time in the table
dbconnection.commit() # write the changes to database
return
if (after.channel == None): # check if the user left the voicechat
print(str(member) + " left the Voicechat")
result = dbcursor.execute("SELECT startTime FROM VcActive WHERE user = ?", [member.id]).fetchone()[
0] # get the join time from database
dbcursor.execute("DELETE FROM VcActive WHERE user=?", [member.id]) # delete the join time entry
xp = (time() - result) / 60 / minutesPerVcXP # calculate the XP
result = dbcursor.execute("SELECT vcXP FROM MESSAGES WHERE user=? AND server = ?",
[member.id, member.guild.id]).fetchone()[
0] # update the user Table and set the new voiceXP
dbcursor.execute("UPDATE MESSAGES SET vcXP = ? WHERE user = ? AND server = ?",
[result + round(xp), member.id, member.guild.id])
dbconnection.commit() # write the changes to disk
return
elif (before.channel == None): # check if a user joins the voicechat
print(str(member) + " joined the Voicechat " + str(after.channel))
dbcursor.execute("INSERT INTO VcActive VALUES (?, ?)",
[member.id, round(time())]) # insert the current time in the database
dbconnection.commit() # write the changes to database
return
# _ _
# | | | |
# | | ___ __ __ ___ | |
# | | / _ \\ \ / / / _ \| |
# | || __/ \ V / | __/| |
# |_| \___| \_/ \___||_|
#
#
@bot.command(brief="shows your current XP and level")
@commands.cooldown(1, cooldownTime, commands.BucketType.user)
async def level(ctx,
user: discord.Member = None): # shows your current XP and level, as argument you can give a different user
if (user == None): # check if the message author submitted a different user to check, if not use the author
user = ctx.message.author
xp = dbcursor.execute("SELECT textXP, reactionXP, vcXP FROM MESSAGES WHERE user=? AND server = ?",
[user.id, ctx.message.guild.id]).fetchone() # get the xp of the user from database
unsorted = dbcursor.execute("SELECT user, textXP, reactionXP, vcXP FROM MESSAGES WHERE server = ?",
[ctx.message.guild.id]).fetchall() # get all users from the database (for the ranking)
ranking = [] # to this variable we will later add the users sorted
while len(unsorted) > 0: # do this while we have entries in unsorted
lowest = unsorted[
0] # just set the first entries in lowest, so we can later overwrite it if we find a user with less XP
for entries in unsorted: # go through every user, calculate the XP and check if its lower than the current lowest
if ((entries[1] + entries[2] + entries[3]) <= (lowest[1] + lowest[2] + lowest[3])):
lowest = entries # if the xp is lower, write the user to lowest
unsorted.remove(lowest) # after checking every user, remove the lowest from unsorted and add it to ranking
ranking.append(lowest)
for entries in ranking: # try to find the user in the ranking array, to get his rank.
if (user.id == entries[0]):
rank = len(ranking) - ranking.index(entries)
tempXP = xp[0] + xp[1] + xp[2] # the XP the user has in this level
level = 0 # the current level
levelXP = 0 # the XP the user needs for the level
while (tempXP > 0): # while the XP is over 0, calculate the XP needed fo this level and subtract it from tempXP
levelXP = base * (factor ** (level))
tempXP = tempXP - levelXP
level = level + 1
level = level - 1 # subtract one level, because the last level the user didn't reached
username = str(user.display_name) # get the username
embed = discord.Embed(title="Stats of " + username,
description="Rank " + str(rank) + " of " + str(len(ranking))) # make the response message
embed.set_thumbnail(url=user.avatar_url)
embed.add_field(name="Text XP", value=xp[0])
embed.add_field(name="Reaction XP", value=xp[1])
embed.add_field(name="Voice XP", value=xp[2])
embed.add_field(name="Total XP", value=xp[0] + xp[1] + xp[2])
embed.add_field(name="Level", value=level)
embed.add_field(name="Progress", value=str(round(levelXP + tempXP)) + "/" + str(round(levelXP)) + " (" + str(
round((levelXP + tempXP) / levelXP * 100)) + "%)")
await ctx.message.channel.send(embed=embed) # send the response message
# _ _ _ _
# | | | | | | | |
# | | ___ __ _ __| | ___ _ __ | |__ ___ __ _ _ __ __| |
# | | / _ \ / _` | / _` | / _ \| '__|| '_ \ / _ \ / _` || '__| / _` |
# | || __/| (_| || (_| || __/| | | |_) || (_) || (_| || | | (_| |
# |_| \___| \__,_| \__,_| \___||_| |_.__/ \___/ \__,_||_| \__,_|
#
#
@bot.command(brief="shows the leaderboard")
@commands.cooldown(1, cooldownTime, commands.BucketType.user)
async def leaderboard(ctx):
if reactOnValidCommand: await ctx.message.add_reaction("")
unsorted = dbcursor.execute("SELECT user, textXP, reactionXP, vcXP FROM MESSAGES WHERE server = ?",
[ctx.message.guild.id]).fetchall() # get all users from the database (for the ranking)
ranking = [] # to this variable we will later add the users sorted
while len(unsorted) > 0: # do this while we have entries in unsorted
lowest = unsorted[
0] # just set the first entries in lowest, so we can later overwrite it if we find a user with less XP
for entries in unsorted: # go through every user, calculate the XP and check if its lower than the current lowest
if ((entries[1] + entries[2] + entries[3]) <= (lowest[1] + lowest[2] + lowest[3])):
lowest = entries # if the xp is lower, write the user to lowest
unsorted.remove(lowest) # after checking every user, remove the lowest from unsorted and add it to ranking
ranking.append(lowest)
while len(ranking) > 10: # remove the last user, while the length is over 10
ranking.remove(ranking[0])
badges = [":first_place: ", ":second_place: ", ":third_place: ", ":four: ", ":five: ", ":six: ", ":seven: ",
":eight: ", ":nine: ", ":keycap_ten: "] # the emoji in front of the username
message = "" # in this variable we will prepare in the next step the response
for entries in reversed(
ranking): # loop through every user in reverse order to get the best first and add his statistics to message
message = message + badges[len(ranking) - ranking.index(entries) - 1] + ": <@" + str(
entries[0]) + "> **Total:** " + str(entries[1] + entries[2] + entries[3]) + " XP (**Text:** " + str(
entries[1]) + " + **Reaction:** " + str(entries[2]) + " + **VC:** " + str(entries[3]) + ")\n"
embed = discord.Embed(title="Leaderboard", description=message) # make the response Box
await ctx.message.channel.send(embed=embed) # print the response box
# _
# (_)
# _ __ _ _ __ __ _
# | '_ \ | || '_ \ / _` |
# | |_) || || | | || (_| |
# | .__/ |_||_| |_| \__, |
# | | __/ |
# |_| |___/
@bot.command(pass_context=True, brief="prints the ping time of the bot")
@commands.cooldown(1, cooldownTime, commands.BucketType.user)
async def ping(ctx): # prints the ping and the time the bot needed to process this command
now = datetime.utcnow() # get the current time
if reactOnValidCommand: await ctx.message.add_reaction("")
delta = round((
now.microsecond - ctx.message.created_at.microsecond) / 1000) # subtract the time the message was created from the current time in microseconds), convert this to milliseconds and round
embed = discord.Embed(title=":ping_pong: | Pong!", description="```prolog\nLatency:: " + str(
round(bot.latency * 1000)) + "ms\nResponse :: " + str(
delta) + "ms```") # make the response, we format it as code and select prolog as language for nice coloring
await ctx.message.channel.send(embed=embed) # send the prepared message
# _ _ __ _ _
# (_)(_) / _| | | | |
# ___ _ __ ___ ___ _ _ | |_ _ _ | |_ ___ __ __| |_
# / _ \| '_ ` _ \ / _ \ | || || _|| | | | | __| / _ \\ \/ /| __|
# | __/| | | | | || (_) | | || || | | |_| | | |_ | __/ > < | |_
# \___||_| |_| |_| \___/ | ||_||_| \__, | \__| \___|/_/\_\ \__|
# _/ | __/ |
# |__/ |___/
@bot.command(brief="prints the text as emojis")
@commands.cooldown(1, cooldownTime, commands.BucketType.user)
async def emoji(ctx, *message: str): # emojifies the string the user give as parameter
if reactOnValidCommand: await ctx.message.add_reaction("")
temp = ""
for messages in message: # because every word will be formatted as parameter by discord.py, we have to make a long string again
temp = temp + messages + " "
messageNew = ""
for char in temp: # process every character one by one
char = char.lower() # convert it to lower (e.g. Aa ==> aa)
if char in "abcdefghijklmnopqrstuvwxyz": # check if the char is a letter
messageNew = messageNew + ":regional_indicator_" + char + ":" # if yes we add to the new message the emoji of the letter
elif char in "1234567890": # if the character is a number we have to use a different emoji
numbers = {"0": 'zero', "1": 'one', "2": 'two', "3": 'three', "4": 'four', "5": 'five', "6": 'six',
"7": 'seven', "8": 'eight', "9": 'nine', }
messageNew = messageNew + ":" + numbers[char] + ":"
elif char == "?": # the emoji for ?
messageNew = messageNew + ":question:"
elif char == "!": # the emoji for !
messageNew = messageNew + ":exclamation:"
else: # if we can'T find a suitable emoji, just add the raw char
messageNew = messageNew + char
await ctx.message.channel.send(messageNew) # send the formatted message
# _ _
# | || |
# _ __ ___ | || |
# | '_ \ / _ \ | || |
# | |_) || (_) || || |
# | .__/ \___/ |_||_|
# | |
# |_|
@bot.command(pass_context=True, brief="starts a poll",
description="starts a poll, please give as first argument the question (for sentences please use \") and then the possibilities (leave empty for yes or no)")
@commands.cooldown(1, cooldownTime, commands.BucketType.user)
async def poll(ctx, question, *options: str): # this is a tool to create a poll
if reactOnValidCommand: await ctx.message.add_reaction("")
if len(options) <= 1: # check if options were supplied, if not add yes and no to the options
options = list(options)
options.append("yes")
options.append("no")
options = tuple(options)
if len(options) > 9: # we can only process 9 arguments at the moment (emoji 1 to 9)
await ctx.message.channel.send(
'You cannot make a poll for more than 9 things!') # if the user added more arguments, print a error message
return
if len(options) == 2 and options[0] == 'yes' and options[
1] == 'no': # select the reaction emojis, ✅ and ❌ for yes or no and numbers one to 9 for the rest
reactions = ['', '']
else:
reactions = ['1⃣', '2⃣', '3⃣', '4⃣', '5⃣', '6⃣', '7⃣', '8⃣', '9⃣']
description = ""
for x, option in enumerate(
options): # make a dict from options and process every entry, x is the key and option the value
description += '\n {} {}'.format(reactions[x],
option) # add to the description for every entry in options one line with the emoji and the answer
embed = discord.Embed(title=question, description=description) # prepare the response
await ctx.message.channel.send("@everyone") # tag everyone, for the new survey
react_message = await ctx.message.channel.send(embed=embed) # print the survey and save the message to a variable
polls[str(react_message.id)] = [react_message,
ctx.message.author.id] # save the react message and the userid to the polls array to access it later
for reaction in reactions[:len(
options)]: # for every reaction add an entry to the reaction database and add it to the message, that the user can click it
dbcursor.execute("INSERT INTO poll VALUES (?, ?, 0)", [react_message.id, reaction])
await react_message.add_reaction(reaction)
embed.set_footer(
text='Poll ID: {}'.format(react_message.id)) # add the poll id to the message (needed to get the results)
await react_message.edit(embed=embed)
# _ _ _ _
# | || | | || |
# _ __ ___ | || | _ __ ___ ___ _ _ | || |_
# | '_ \ / _ \ | || | | '__| / _ \/ __|| | | || || __|
# | |_) || (_) || || | | | | __/\__ \| |_| || || |_
# | .__/ \___/ |_||_| |_| \___||___/ \__,_||_| \__|
# | |
# |_|
@bot.command(pass_context=True, brief="shows the result of a poll, give the poll ID as argument")
@commands.cooldown(1, cooldownTime, commands.BucketType.user)
async def result(ctx, id): # this function prints the result of a poll
if reactOnValidCommand: await ctx.message.add_reaction("")
poll_message = polls[str(id)][0] # get the poll message from the variable
poll_owner = polls[str(id)][1]
if (poll_owner != ctx.message.author.id): # check if the poll owner wants the result, or someone else
await ctx.message.channel.send("You can only get the results of your poll.")
return
embed = poll_message.embeds[0] # get the embed (the content)
del polls[str(id)] # delete the poll from the poll message array
nonformatted_options = [x.strip() for x in poll_message.embeds[0].description.split(
'\n')] # split the poll options (split every line and remove all leading and trailing spaces)
opt_dict = {}
for options in nonformatted_options: # for every option: split on the space between emoji and text and put it in a dict, with the emoji as key and the emoji + the text as value
options = options.split(" ", 1)
opt_dict[options[0]] = options[0] + " " + options[1]
request = dbcursor.execute("SELECT calls, reaction FROM poll WHERE pollID = ?",
[id]).fetchall() # get the votes from the database
description = ""
for results in request: # loop through the entries of the database and make the result
description = description + "\n" + opt_dict[results[1]] + ": " + str(results[0]) + " votes"
embed = discord.Embed(title=poll_message.embeds[0].title, description=description) # prepare the result
embed.set_footer(
text='ended on ' + datetime.now().strftime("%d.%m.%Y %H:%M:%S")) # set as footer the end time of the poll
await poll_message.edit(embed=embed) # edit the origin message and print the results
embed2 = discord.Embed(title=" ",
description="You can find the result of the poll in the original message [here](" + poll_message.jump_url + ").") # This message will be printed to the end of the chat with a link to the original (where the results are)
await ctx.message.channel.send(embed=embed2) # print the result message from one line up
dbcursor.execute("DELETE FROM poll where pollID = ?", [id]) # delete the entries from the poll in the database
dbconnection.commit() # write the database to disk
# _____
# |_ _|
# | | _ __ ___ __ _ __ _ ___ ___
# | | | '_ ` _ \ / _` |/ _` |/ _ \/ __|
# _| |_| | | | | | (_| | (_| | __/\__ \
# |_____|_| |_| |_|\__,_|\__, |\___||___/
# __/ |
# |___/
@bot.command(pass_context=True, brief="sends a random cat image")
@commands.cooldown(1, cooldownTime, commands.BucketType.user)
async def cat(ctx):
if reactOnValidCommand: await ctx.message.add_reaction("")
r = get("https://api.thecatapi.com/v1/images/search?size=full") # get random cat image
answer = loads(r.text)
extension = answer[0]["url"].split(".")[-1] # get the file extension
r = get(answer[0]["url"]) # get the url to the cat
image_data = BytesIO(r.content) # download the image and load it into BytesIO
image_data.seek(0)
await ctx.send(file=discord.File(image_data, 'cat.' + extension)) # send the cat image
@bot.command(pass_context=True, brief="sends a random dog image")
@commands.cooldown(1, cooldownTime, commands.BucketType.user)
async def dog(ctx):
if reactOnValidCommand: await ctx.message.add_reaction("")
r = get("https://random.dog/woof.json") # get random dog image
answer = loads(r.text)
extension = answer["url"].split(".")[-1] # get the file extension
r = get(answer["url"]) # get the url to the dog
image_data = BytesIO(r.content) # download the image and load it into BytesIO
image_data.seek(0)
await ctx.send(file=discord.File(image_data, 'dog.' + extension)) # send the dog image
@bot.command(pass_context=True, brief="sends a random fail gif")
@commands.cooldown(1, cooldownTime, commands.BucketType.user)
async def fail(ctx):
if reactOnValidCommand: await ctx.message.add_reaction("")
r = get(
"https://api.giphy.com/v1/gifs/random?api_key=0UTRbFtkMxAplrohufYco5IY74U8hOes&tag=fail&pg-13") # get random fail image
answer = loads(r.text)
r = get(answer["data"]["images"]["downsized_medium"]["url"]) # get the url to the fail
image_data = BytesIO(r.content) # download the image and load it into BytesIO
image_data.seek(0)
await ctx.send(file=discord.File(image_data, 'fail.gif')) # send the fail image
@bot.command(pass_context=True, brief="sends a random upload from jensmemes.tilera.xyz")
@commands.cooldown(1, cooldownTime, commands.BucketType.user)
async def jensmeme(ctx):
if reactOnValidCommand: await ctx.message.add_reaction("")
r = get("https://api.tilera.xyz/jensmemes/v1/random") # get random upload
await ctx.send(loads(r.text)["meme"]["link"]) # send the fail image
# _ _
# | | | |
# | |__| | __ _ _ __ __ _ _ __ ___ __ _ _ __
# | __ |/ _` | '_ \ / _` | '_ ` _ \ / _` | '_ \
# | | | | (_| | | | | (_| | | | | | | (_| | | | |
# |_| |_|\__,_|_| |_|\__, |_| |_| |_|\__,_|_| |_|
# __/ |
#
# |___/
@bot.command(pass_context=True, brief="Starts a hangman game in this channel")
@commands.cooldown(1, cooldownTime, commands.BucketType.user)
async def hangman(ctx):
global hangmanMessages
if reactOnValidCommand: await ctx.message.add_reaction("")
embed = discord.Embed(title="Hangman", description=ctx.message.author.display_name + " wants to play hangman. Please wait for him to set a word") # make the response message
message = await ctx.message.channel.send(embed=embed) # send the response message
hangmanMessages[str(message.id)] = message
dbcursor.execute("INSERT INTO hangman (gameID, owner, word, right, wrong, channel) VALUES (\"" + str(message.id) + "\", \"" + str(ctx.message.author.id) + "\", \"\", \"\", \"\", \"" + str(ctx.channel.id) + "\")")
dbconnection.commit()
await ctx.message.author.send("Please give me a word.")
# ___ ___ _ ______ _
# | \/ | (_) | ___ \ | |
# | . . | _ _ ___ _ ___ | |_/ / ___ | |_
# | |\/| || | | |/ __|| | / __|| ___ \ / _ \ | __|
# | | | || |_| |\__ \| || (__ | |_/ /| (_) || |_
# \_| |_/ \__,_||___/|_| \___|\____/ \___/ \__|
#
#
@bot.command(brief="adds a song to the playlist")
@commands.cooldown(1, cooldownTime, commands.BucketType.user)
async def play(ctx, songURL: str):
if reactOnValidCommand: await ctx.message.add_reaction("")
global player # import the global variables needed
global playerServer
global downloadQue
try:
channel = ctx.author.voice.channel # get the current voicechat the user is in
except: # if we can't get the voice channel, the user is not in one ==> print an error
await ctx.message.channel.send("To use the music bot you have to be in a voice chat")
return
if (player == None): # if the music player is currently not connected to a server
await channel.connect() # connect to this chat
player = ctx.voice_client # save the voice client for later use
playerServer = ctx.message.guild.id # save the music bot server id to variable
if (
playerServer != ctx.message.guild.id): # check if the music bot is at the moment on this server, if not print a error message
await ctx.message.channel.send(
"The Bot is currently connected to a different channel, please wait until he is finished there")
return
r = get("https://www.youtube.com/oembed?format=json&url=" + songURL) # check if video exists and get the title
if (r.status_code != 200): # if youtube doesn't respond with 200, there was an error finding the song
await ctx.message.channel.send("Can't find the song")
return
await ctx.message.channel.send("Adding `" + loads(r.text)["title"] + "` to que.") # print the user a status message
playerQue.append(songURL)
titleQue.append(loads(r.text)["title"])
@bot.command(brief="skips the current song in playlist")
@commands.cooldown(1, cooldownTime, commands.BucketType.user)
async def skip(ctx):
try:
channel = ctx.author.voice.channel # get the current voicechat the user is in
except: # if we can't get the voice channel, the user is not in one ==> print an error
await ctx.message.channel.send("To use the music bot you have to be in a voice chat")
return
if reactOnValidCommand: await ctx.message.add_reaction("")
global player # import the global variable
player.stop() # stop the player (daemon think song ended ==> plays next one)
await ctx.message.channel.send("Skipped current song") # print the status to the console
@bot.command(brief="Prints the current music que")
@commands.cooldown(1, cooldownTime, commands.BucketType.user)
async def que(ctx):
if reactOnValidCommand: await ctx.message.add_reaction("")
global titleQue # import the global variable
message = "**Musicbot Que:**\n **[current] " + titleQue[
0] + " **" # prepare the message and add the current playing first in bold
for entries in titleQue[1:]: # scroll through the entries and add all songs to the response
message = message + "\n" + entries
await ctx.message.channel.send(message) # send the prepared message
@bot.command(brief="stop the music bot and clear the que")
@commands.cooldown(1, cooldownTime, commands.BucketType.user)
async def stop(ctx):
if reactOnValidCommand: await ctx.message.add_reaction("")
try:
channel = ctx.author.voice.channel # get the current voicechat the user is in
except: # if we can't get the voice channel, the user is not in one ==> print an error
await ctx.message.channel.send("To use the music bot you have to be in a voice chat")
return
global player # import the global variables
global playerQue
global titleQue
global downloadQue
global playerServer
if (playerServer != ctx.message.guild.id): # check if the music bot runs on this server
await ctx.message.channel.send("You can't stop the music bot on a different server.")
return
playerQue = [] # delete all ques
titleQue = []
downloadQue = []
player.stop() # stop the current song
await player.disconnect() # disconnect from the voice chat
player = None # clear the player variable
playerServer = None # allow everyone to invite the music bot
for files in listdir("."): # delete all mp3 files
if files.endswith(".mp3"):
remove(files)
@bot.command(
brief="changes the volume of the music bot") # with this command you can change the volume of the music bot
@commands.cooldown(1, cooldownTime, commands.BucketType.user)
async def volume(ctx, volume: int):
if reactOnValidCommand: await ctx.message.add_reaction("")
try:
channel = ctx.author.voice.channel # get the current voicechat the user is in
except: # if we can't get the voice channel, the user is not in one ==> print an error
await ctx.message.channel.send("To use the music bot you have to be in a voice chat")
return
global audioPlayer # import hte global audio player
if (volume < 0) or (volume > 100): # check if the volume is in a percent range
ctx.message.channel.send("Volume has to be between 0 and 100")
else:
audioPlayer.volume = volume / 100 # change the volume
async def checkForNextSong(): # background task, that runs every second and checks if the song ended
global player # import the global variables
global playerQue
global playerServer
global playing
global titleQue
global audioPlayer
while True: # catch all errors (dont crash when a error occurs)
try:
if (player != None) and not player.is_playing() and (
len(playerQue) > 0): # check if the player is active and the song ended
print("song ended")
if (playing): # check if the player played previously
print("clear last")
playerQue.remove(playerQue[0]) # remove the first entry from the que and the first title
titleQue.remove(titleQue[0])
playing = False # set playing to false
if (len(playerQue) == 0): # if the que is empty leave the voicechat and clear the player variable
print("disconnect")
await player.disconnect()
player = None
playerServer = None # allow everyone to invite the music bot
else:
playing = True # set playing to true and play the next file
print("playing " + playerQue[0])
data = YoutubeDL().extract_info(playerQue[0], download=False)
if 'entries' in data:
# take first item from a playlist
data = data['entries'][0]
for format in data["formats"]:
if(format["format_id"] == "140"):
try:
filename = data["formats"][0]["manifest_url"]
except:
filename = data["formats"][0]["url"]
print("start playback: " + filename)
audioPlayer = discord.PCMVolumeTransformer(discord.FFmpegPCMAudio(filename, **{
'options': '-vn'})) # convert the audio player to a volume audio player
player.play(audioPlayer)
await sleep(1) # sleep 1 second and allow the bot to run different tasks
except:
pass
@tasks.loop(seconds=60)
async def hearBeat():
if(heartBeatEnabled):
r = get(heartBeatURL)
hearBeat.start()
bot.loop.create_task(checkForNextSong()) # start the music bot task in background
bot.run(token, bot=botAccount) # start the bot with the options in config.py