2020-04-02 18:52:54 +02:00
#!/usr/bin/env python3
2020-04-02 11:40:56 +02:00
import discord
2020-04-10 16:39:32 +02:00
from discord . ext import commands , tasks
2020-04-02 11:40:56 +02:00
from discord . utils import get
from discord import FFmpegPCMAudio
2020-04-02 20:57:04 +02:00
from sqlite3 import connect
2020-04-02 11:40:56 +02:00
from datetime import datetime , timedelta
from config import *
2020-04-10 16:39:32 +02:00
from requests import get
from json import loads
from os . path import isfile
from os import rename , remove
from youtube_dl import YoutubeDL
from time import time
2020-04-10 20:32:49 +02:00
from asyncio import sleep
from threading import Thread
2020-04-02 11:40:56 +02:00
polls = { }
2020-04-10 16:39:32 +02:00
player = None #the Player for the music Bot
playerServer = None #The Server the player is active at the moment
downloadQue = [ ]
playerQue = [ ]
titleQue = [ ]
fileIndex = 0
playing = False
2020-04-02 11:40:56 +02:00
bot = commands . Bot ( command_prefix = prefix )
2020-04-02 20:57:04 +02:00
dbconnection = connect ( ' database.db ' )
2020-04-02 20:51:49 +02:00
dbcursor = dbconnection . cursor ( )
2020-04-02 11:40:56 +02:00
2020-04-02 18:17:24 +02:00
try : #try to create the database tables, if it fails they were created previosly
2020-04-02 11:40:56 +02:00
sql = " CREATE TABLE MESSAGES(user LONG, server LONG, textXP LONG, reactionXP LONG, vcXP LONG) "
sql2 = " CREATE TABLE VcActive (user LONG, startTime LONG) "
sql3 = " CREATE TABLE poll (pollID LONG, reaction STRING, calls LONG) "
2020-04-02 20:51:49 +02:00
dbcursor . execute ( sql )
dbcursor . execute ( sql2 )
dbcursor . execute ( sql3 )
2020-04-02 11:40:56 +02:00
except :
pass
2020-04-10 14:20:40 +02:00
2020-04-02 18:24:54 +02:00
@bot.event #print the username and id to the console and change the game status
2020-04-02 11:40:56 +02:00
async def on_ready ( ) :
print ( ' Logged in as ' )
print ( bot . user . name )
print ( bot . user . id )
print ( ' ------ ' )
2020-04-02 18:17:24 +02:00
await bot . change_presence ( activity = discord . Game ( name = game ) )
2020-04-02 11:40:56 +02:00
2020-04-10 14:20:40 +02:00
#
#
# _ __ ___ __ __ _ __ ___ ___ ___ ___ __ _ __ _ ___
# | '_ \ / _ \\ \ /\ / / | '_ ` _ \ / _ \/ __|/ __| / _` | / _` | / _ \
# | | | || __/ \ V V / | | | | | || __/\__ \\__ \| (_| || (_| || __/
# |_| |_| \___| \_/\_/ |_| |_| |_| \___||___/|___/ \__,_| \__, | \___|
# __/ |
# |___/
2020-04-02 11:40:56 +02:00
@bot.event
2020-04-02 18:17:24 +02:00
async def on_message ( message ) : #this will run on every message
2020-04-10 21:00:30 +02:00
if ( message . guild == None ) and " 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)
2020-04-10 20:41:29 +02:00
2020-04-02 18:17:24 +02:00
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
2020-04-02 11:40:56 +02:00
return
2020-04-02 20:51:49 +02:00
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
2020-04-02 11:40:56 +02:00
result = res . fetchone ( )
if ( result == None ) :
2020-04-02 20:51:49 +02:00
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
2020-04-02 11:40:56 +02:00
else :
messages = result [ 0 ] + messageXP
2020-04-02 20:51:49 +02:00
dbcursor . execute ( " UPDATE MESSAGES SET textXP = ? WHERE user = ? AND server = ? " , [ messages , message . author . id , message . guild . id ] ) #update the textXP value in the Database
2020-04-02 11:40:56 +02:00
2020-04-02 20:51:49 +02:00
dbconnection . commit ( ) #write the database changes to disk
2020-04-02 11:40:56 +02:00
2020-04-02 18:17:24 +02:00
if message . content . startswith ( prefix ) : #check if the message starts with the prefix, if yes process the command
2020-04-02 11:40:56 +02:00
await bot . process_commands ( message )
2020-04-02 20:45:34 +02:00
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. " )
2020-04-02 11:40:56 +02:00
2020-04-10 14:20:40 +02:00
# _ _ _ _
# | | (_) | | | |
# _ __ ___ __ _ ___ | |_ _ ___ _ __ __ _ __| | __| |
# | '__| / _ \ / _` | / __|| __|| | / _ \ | '_ \ / _` | / _` | / _` |
# | | | __/| (_| || (__ | |_ | || (_) || | | | | (_| || (_| || (_| |
# |_| \___| \__,_| \___| \__||_| \___/ |_| |_| \__,_| \__,_| \__,_|
#
#
2020-04-02 11:40:56 +02:00
@bot.event
2020-04-02 18:17:24 +02:00
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
2020-04-02 11:40:56 +02:00
return
2020-04-02 20:51:49 +02:00
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
2020-04-02 11:40:56 +02:00
result = res . fetchone ( )
if ( result == None ) :
2020-04-02 20:51:49 +02:00
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
2020-04-02 11:40:56 +02:00
messages = reactionXP
else :
messages = result [ 0 ] + reactionXP
2020-04-02 20:51:49 +02:00
dbcursor . execute ( " UPDATE MESSAGES SET reactionXP = ? WHERE user = ? AND server = ? " , [ messages , message . user_id , message . guild_id ] ) #update the reactionXP with the new values
2020-04-02 11:40:56 +02:00
try :
2020-04-02 18:17:24 +02:00
polls [ str ( message . message_id ) ] # check if the reaction is on a poll
2020-04-02 20:51:49 +02:00
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 ) ] )
2020-04-02 11:40:56 +02:00
except :
pass
2020-04-02 20:51:49 +02:00
dbconnection . commit ( ) #write the database changes to disk
2020-04-10 14:20:40 +02:00
# _ _
# | | (_)
# _ __ ___ __ _ ___ | |_ _ ___ _ __ _ __ ___ _ __ ___ ___ __ __ ___
# | '__| / _ \ / _` | / __|| __|| | / _ \ | '_ \ | '__| / _ \| '_ ` _ \ / _ \ \ \ / / / _ \
# | | | __/| (_| || (__ | |_ | || (_) || | | | | | | __/| | | | | || (_) | \ V / | __/
# |_| \___| \__,_| \___| \__||_| \___/ |_| |_| |_| \___||_| |_| |_| \___/ \_/ \___|
#
#
2020-04-02 11:40:56 +02:00
@bot.event
async def on_raw_reaction_remove ( message ) :
try :
2020-04-02 18:17:24 +02:00
polls [ str ( message . message_id ) ] #check if the message is a poll
2020-04-02 20:51:49 +02:00
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 ) ] )
2020-04-02 11:40:56 +02:00
except :
pass
2020-04-02 20:51:49 +02:00
dbconnection . commit ( ) # write the database changes to disk
2020-04-02 11:40:56 +02:00
2020-04-10 14:20:40 +02:00
# _ _ _ _ _
# (_) | | | | | | | |
# __ __ ___ _ ___ ___ ___ | |__ __ _ | |_ _ _ _ __ __| | __ _ | |_ ___
# \ \ / / / _ \ | | / __| / _ \ / __|| '_ \ / _` || __| | | | || '_ \ / _` | / _` || __| / _ \
# \ V / | (_) || || (__ | __/| (__ | | | || (_| || |_ | |_| || |_) || (_| || (_| || |_ | __/
# \_/ \___/ |_| \___| \___| \___||_| |_| \__,_| \__| \__,_|| .__/ \__,_| \__,_| \__| \___|
# | |
# |_|
2020-04-02 11:40:56 +02:00
@bot.event
2020-04-02 18:17:24 +02:00
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
2020-04-02 11:40:56 +02:00
return
2020-04-02 18:17:24 +02:00
if not before . afk and after . afk : #check if the user moved from not afk to afk
2020-04-02 11:40:56 +02:00
print ( str ( member ) + " is now AFK " )
2020-04-02 20:51:49 +02:00
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 entrie from the voicechat in the database
2020-04-02 18:17:24 +02:00
xp = ( time ( ) - result ) / minutesPerVcXP #calculate the xp
2020-04-02 20:51:49 +02:00
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
2020-04-02 11:40:56 +02:00
return
2020-04-02 18:17:24 +02:00
if before . afk and not after . afk : #check if the user moved from afk back to active
2020-04-02 11:40:56 +02:00
print ( str ( member ) + " is active again " )
2020-04-02 20:51:49 +02:00
dbcursor . execute ( " INSERT INTO VcActive VALUES (?, ?) " , [ member . id , round ( time ( ) ) ] ) #insert the current time in the table
dbconnection . commit ( ) #write the changes to database
2020-04-02 11:40:56 +02:00
return
2020-04-02 18:17:24 +02:00
if ( after . channel == None ) : #check if the user left the voicechat
2020-04-02 11:40:56 +02:00
print ( str ( member ) + " left the Voicechat " )
2020-04-02 20:51:49 +02:00
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
2020-04-02 18:17:24 +02:00
xp = ( time ( ) - result ) / 60 / minutesPerVcXP #calculate the XP
2020-04-02 20:51:49 +02:00
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
2020-04-02 11:40:56 +02:00
return
2020-04-02 18:17:24 +02:00
elif ( before . channel == None ) : #check if a user joins the voicechat
2020-04-02 11:40:56 +02:00
print ( str ( member ) + " joined the Voicechat " + str ( after . channel ) )
2020-04-02 20:51:49 +02:00
dbcursor . execute ( " INSERT INTO VcActive VALUES (?, ?) " , [ member . id , round ( time ( ) ) ] ) #insert the current time in the database
dbconnection . commit ( ) #write the changes to databasr
2020-04-02 11:40:56 +02:00
return
2020-04-10 14:20:40 +02:00
# _ _
# | | | |
# | | ___ __ __ ___ | |
# | | / _ \\ \ / / / _ \| |
# | || __/ \ V / | __/| |
# |_| \___| \_/ \___||_|
#
#
2020-04-02 11:40:56 +02:00
@bot.command ( brief = " shows your current XP and level " )
2020-04-02 18:17:24 +02:00
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
2020-04-02 11:40:56 +02:00
2020-04-02 20:51:49 +02:00
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)
2020-04-02 18:17:24 +02:00
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 entrie 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
2020-04-02 11:40:56 +02:00
ranking . append ( lowest )
2020-04-02 18:17:24 +02:00
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
2020-04-02 11:40:56 +02:00
levelXP = base * ( factor * * ( level ) )
tempXP = tempXP - levelXP
level = level + 1
2020-04-02 18:17:24 +02:00
level = level - 1 #subtract one level, because the last level the user didn't reached
2020-04-02 11:40:56 +02:00
2020-04-02 18:17:24 +02:00
username = str ( user . name ) #get the username
embed = discord . Embed ( title = " Stats of " + username , description = " Rank " + str ( rank ) + " of " + str ( len ( ranking ) ) ) #make the response message
2020-04-02 11:40:56 +02:00
embed . set_thumbnail ( url = user . avatar_url )
2020-04-02 18:17:24 +02:00
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 ] )
2020-04-02 11:40:56 +02:00
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 ) ) + " % ) " )
2020-04-02 18:17:24 +02:00
await ctx . message . channel . send ( embed = embed ) #send the response message
2020-04-02 11:40:56 +02:00
2020-04-10 14:20:40 +02:00
# _ _ _ _
# | | | | | | | |
# | | ___ __ _ __| | ___ _ __ | |__ ___ __ _ _ __ __| |
# | | / _ \ / _` | / _` | / _ \| '__|| '_ \ / _ \ / _` || '__| / _` |
# | || __/| (_| || (_| || __/| | | |_) || (_) || (_| || | | (_| |
# |_| \___| \__,_| \__,_| \___||_| |_.__/ \___/ \__,_||_| \__,_|
#
#
2020-04-02 11:40:56 +02:00
@bot.command ( brief = " shows the leaderboard " )
async def leaderboard ( ctx ) :
2020-04-02 20:51:49 +02:00
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)
2020-04-02 18:17:24 +02:00
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 entrie 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
2020-04-02 11:40:56 +02:00
ranking . append ( lowest )
2020-04-02 18:17:24 +02:00
while len ( ranking ) > 10 : #remove the last user, while the length is over 10
2020-04-02 11:40:56 +02:00
ranking . remove ( ranking [ 0 ] )
2020-04-02 18:17:24 +02:00
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 andd his statistics to message
2020-04-03 09:56:57 +02:00
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 "
2020-04-02 18:17:24 +02:00
embed = discord . Embed ( title = " Leaderboard " , description = message ) #make the response Box
await ctx . message . channel . send ( embed = embed ) #print the ressponse box
2020-04-02 11:40:56 +02:00
2020-04-10 14:20:40 +02:00
# _
# (_)
# _ __ _ _ __ __ _
# | '_ \ | || '_ \ / _` |
# | |_) || || | | || (_| |
# | .__/ |_||_| |_| \__, |
# | | __/ |
# |_| |___/
2020-04-02 11:40:56 +02:00
@bot.command ( pass_context = True , brief = " prints the ping time of the bot " )
2020-04-02 18:17:24 +02:00
async def ping ( ctx ) : #prints the ping and the time the bot needed to process this command
now = datetime . utcnow ( ) #get the current time
delta = round ( ( now . microsecond - ctx . message . created_at . microsecond ) / 1000 ) #substract the time the message was created from the current time 8in microsecconds), convert this to millisecconds and round
embed = discord . Embed ( title = " :ping_pong: | Pong! " , description = " ```prolog \n Latency:: " + str ( round ( bot . latency * 1000 ) ) + " ms \n Response :: " + str ( delta ) + " ms``` " ) #make the response, we format it as code and select prolog as language for nice cloloring
2020-04-02 11:40:56 +02:00
2020-04-02 18:17:24 +02:00
await ctx . message . channel . send ( embed = embed ) #send the prepared message
2020-04-02 11:40:56 +02:00
2020-04-10 14:20:40 +02:00
# _ _ __ _ _
# (_)(_) / _| | | | |
# ___ _ __ ___ ___ _ _ | |_ _ _ | |_ ___ __ __| |_
# / _ \| '_ ` _ \ / _ \ | || || _|| | | | | __| / _ \\ \/ /| __|
# | __/| | | | | || (_) | | || || | | |_| | | |_ | __/ > < | |_
# \___||_| |_| |_| \___/ | ||_||_| \__, | \__| \___|/_/\_\ \__|
# _/ | __/ |
# |__/ |___/
2020-04-02 11:40:56 +02:00
@bot.command ( brief = " prints the text as emojies " )
2020-04-02 18:17:24 +02:00
async def emoji ( ctx , * message : str ) : #emojifies the string the user give as parameter
2020-04-02 11:40:56 +02:00
temp = " "
2020-04-02 18:17:24 +02:00
for messages in message : #because every word will be formatted as parameter by discord.py, we have to make a long string again
2020-04-02 11:40:56 +02:00
temp = temp + messages + " "
messageNew = " "
2020-04-02 18:17:24 +02:00
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
2020-04-02 11:40:56 +02:00
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 ] + " : "
2020-04-02 18:17:24 +02:00
elif char == " ? " : #the emoji for ?
2020-04-02 11:40:56 +02:00
messageNew = messageNew + " :question: "
2020-04-02 18:17:24 +02:00
elif char == " ! " : #the emoji for !
2020-04-02 11:40:56 +02:00
messageNew = messageNew + " :exclamation: "
2020-04-02 18:17:24 +02:00
else : #if we can'T find a suitable emoji, just add the raw char
2020-04-02 11:40:56 +02:00
messageNew = messageNew + char
2020-04-02 18:17:24 +02:00
await ctx . message . channel . send ( messageNew ) #send the formatted message
2020-04-02 11:40:56 +02:00
2020-04-10 14:20:40 +02:00
# _ _
# | || |
# _ __ ___ | || |
# | '_ \ / _ \ | || |
# | |_) || (_) || || |
# | .__/ \___/ |_||_|
# | |
# |_|
2020-04-02 11:40:56 +02:00
@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 posibilities (leave empty for yes or no) " )
2020-04-02 18:17:24 +02:00
async def poll ( ctx , question , * options : str ) : #this is a tool to create a poll
if len ( options ) < = 1 : #check if options were supplied, if not add yes and no to the options
2020-04-02 11:40:56 +02:00
options = list ( options )
options . append ( " yes " )
options . append ( " no " )
options = tuple ( options )
2020-04-02 18:17:24 +02:00
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
2020-04-02 11:40:56 +02:00
return
2020-04-02 18:17:24 +02:00
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
2020-04-02 11:40:56 +02:00
reactions = [ ' ✅ ' , ' ❌ ' ]
else :
reactions = [ ' 1⃣ ' , ' 2⃣ ' , ' 3⃣ ' , ' 4⃣ ' , ' 5⃣ ' , ' 6⃣ ' , ' 7⃣ ' , ' 8⃣ ' , ' 9⃣ ' ]
2020-04-02 18:17:24 +02:00
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 otions 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 #save the react message to the polls array to acces 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
2020-04-02 20:51:49 +02:00
dbcursor . execute ( " INSERT INTO poll VALUES (?, ?, 0) " , [ react_message . id , reaction ] )
2020-04-02 11:40:56 +02:00
await react_message . add_reaction ( reaction )
2020-04-02 18:17:24 +02:00
embed . set_footer ( text = ' Poll ID: {} ' . format ( react_message . id ) ) #add the poll id to the message (needed to get the results)
2020-04-02 11:40:56 +02:00
await react_message . edit ( embed = embed )
2020-04-10 14:20:40 +02:00
# _ _ _ _
# | || | | || |
# _ __ ___ | || | _ __ ___ ___ _ _ | || |_
# | '_ \ / _ \ | || | | '__| / _ \/ __|| | | || || __|
# | |_) || (_) || || | | | | __/\__ \| |_| || || |_
# | .__/ \___/ |_||_| |_| \___||___/ \__,_||_| \__|
# | |
# |_|
2020-04-02 11:40:56 +02:00
@bot.command ( pass_context = True , brief = " shows the result of a poll, give the poll ID as argument " )
2020-04-02 18:17:24 +02:00
async def result ( ctx , id ) : #this function prints the result of a poll
poll_message = polls [ str ( id ) ] #get the poll message from the variable
embed = poll_message . embeds [ 0 ] #get the embed (the content)
del polls [ str ( id ) ] #delte the poll from the poll message array
unformatted_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 unformatted_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 ]
2020-04-02 20:51:49 +02:00
request = dbcursor . execute ( " SELECT calls, reaction FROM poll WHERE pollID = ? " , [ id ] ) . fetchall ( ) #get the votes from the database
2020-04-02 18:17:24 +02:00
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 = ' enden 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 origina lmessage and print the results
2020-04-02 18:35:53 +02:00
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
2020-04-02 20:51:49 +02:00
dbcursor . execute ( " DELETE FROM poll where pollID = ? " , [ id ] ) #delete the entries from the poll in the database
dbconnection . commit ( ) #write the database to disk
2020-04-02 18:17:24 +02:00
2020-04-10 16:39:32 +02:00
# ___ ___ _ ______ _
# | \/ | (_) | ___ \ | |
# | . . | _ _ ___ _ ___ | |_/ / ___ | |_
# | |\/| || | | |/ __|| | / __|| ___ \ / _ \ | __|
# | | | || |_| |\__ \| || (__ | |_/ /| (_) || |_
# \_| |_/ \__,_||___/|_| \___|\____/ \___/ \__|
#
#
@bot.command ( brief = " adds a song to the playlist " )
async def play ( ctx , songURL : str ) :
2020-04-10 21:00:30 +02:00
global player #import the global variables needed
2020-04-10 16:39:32 +02:00
global playerServer
global downloadQue
2020-04-10 14:20:40 +02:00
2020-04-10 16:39:32 +02:00
try :
channel = ctx . author . voice . channel #get the current voicechat the user is in
2020-04-10 21:00:30 +02:00
except : #if we can't get the voice channel, the user is not in one ==> print an error
2020-04-10 16:39:32 +02:00
await ctx . message . channel . send ( " To use the music bot you have to be in a voice chat " )
return
2020-04-10 21:00:30 +02:00
if ( player == None ) : #if the music player is currently not connected to a server
2020-04-10 16:39:32 +02:00
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
2020-04-10 14:20:40 +02:00
2020-04-10 21:00:30 +02:00
if ( playerServer != ctx . message . guild . id ) : #check if the music bot is at the moment on this server, if not print a error message
2020-04-10 16:39:32 +02:00
await ctx . message . channel . send ( " The Bot is currently connected to a different channel, please wait until he is finished there " )
return
2020-04-10 21:00:30 +02:00
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
2020-04-10 16:39:32 +02:00
await ctx . message . channel . send ( " Can ' t find the song " )
return
2020-04-10 21:00:30 +02:00
await ctx . message . channel . send ( " Adding ` " + loads ( r . text ) [ " title " ] + " ` to que. " ) #print the user a status message
downloadQue . append ( [ loads ( r . text ) [ " html " ] . split ( " src= " ) [ 1 ] [ 1 : ] . split ( " \" " ) [ 0 ] , loads ( r . text ) [ " title " ] ] ) #add the title + the url to the download que
2020-04-10 14:20:40 +02:00
2020-04-10 16:39:32 +02:00
@bot.command ( brief = " skipps the current song in playlist " )
async def skip ( ctx ) :
2020-04-10 21:00:30 +02:00
global player # import the global variable
player . stop ( ) #stop the player (daemon think song enden ==> plays next one)
await ctx . message . channel . send ( " Skipped current song " ) #print the status to the console
2020-04-10 16:39:32 +02:00
2020-04-10 20:41:29 +02:00
@bot.command ( brief = " Prints the current music que " )
2020-04-10 17:01:22 +02:00
async def que ( ctx ) :
2020-04-10 21:00:30 +02:00
global titleQue #import the global variable
message = " **Musicbot Que:** \n **[current] " + titleQue [ 0 ] + " ** " #prepare the message and add the current playing first in bold
2020-04-10 17:01:22 +02:00
2020-04-10 21:00:30 +02:00
for entries in titleQue [ 1 : ] : #scroll through the entries and add all songs to the resonse
2020-04-10 17:01:22 +02:00
message = message + " \n " + entries
2020-04-10 21:00:30 +02:00
await ctx . message . channel . send ( message ) #send the prepared message
2020-04-10 17:01:22 +02:00
2020-04-10 21:10:51 +02:00
@bot.command ( brief = " stop the music bot and clear the que " )
async def stop ( ctx ) :
global player #import the global variables
global playerQue
global titleQue
global downloadQue
2020-04-10 21:19:52 +02:00
global playerServer
2020-04-10 21:10:51 +02:00
if ( playerServer != ctx . message . guild . id ) : #check if the music bot runns on this server
await ctx . message . channel . send ( " You can ' t stop the music bot on a different server. " )
return
playerQue = [ ] #delte all ques
titleQue = [ ]
downloadQue = [ ]
player . stop ( ) #stop the current song
2020-04-10 21:16:34 +02:00
await player . disconnect ( ) #disconnect from the voice chat
player = None #clear the player variable
playerServer = None #allow everyone to invite the music bot
remove ( " *.mp3 " ) #delete all mp3 files
2020-04-10 21:10:51 +02:00
2020-04-10 20:41:29 +02:00
2020-04-10 21:00:30 +02:00
async def checkForNextSong ( ) : #background task, that runns every seccond and checks if the song ended
global player #import the global variables
2020-04-10 16:39:32 +02:00
global playerQue
global playerServer
global playing
2020-04-10 17:01:22 +02:00
global titleQue
2020-04-10 16:39:32 +02:00
while True :
2020-04-10 21:00:30 +02:00
if ( player != None ) and not player . is_playing ( ) and ( len ( playerQue ) > 0 ) : #check if the player is active and the song ended
if ( playing ) : #check if the player played previously
remove ( playerQue [ 0 ] ) #delete the last mp3 file
playerQue . remove ( playerQue [ 0 ] ) #remove the first entry from the que and the first title
2020-04-10 16:54:44 +02:00
titleQue . remove ( titleQue [ 0 ] )
2020-04-10 21:00:30 +02:00
playing = False #set playing to false
if ( len ( playerQue ) == 0 ) : #if the que is empty leave the voicechat and cleat the player variable
2020-04-10 16:54:44 +02:00
await player . disconnect ( )
2020-04-10 16:39:32 +02:00
player = None
2020-04-10 21:00:30 +02:00
playerServer = None #allow everyone to invite the music bot
2020-04-10 21:10:51 +02:00
remove ( " *.mp3 " ) #delete all mp3 files
2020-04-10 16:39:32 +02:00
else :
2020-04-10 21:00:30 +02:00
playing = True #set playing to true and play the next file
2020-04-10 16:39:32 +02:00
player . play ( discord . FFmpegPCMAudio ( playerQue [ 0 ] ) )
2020-04-10 21:00:30 +02:00
await sleep ( 1 ) #sleep 1 seccond and allo the bot to run different tasks
2020-04-10 16:39:32 +02:00
async def downloadAudioFiles ( ) :
2020-04-10 21:00:30 +02:00
global downloadQue #import the global variables
2020-04-10 20:32:49 +02:00
global titleQue
2020-04-10 21:00:30 +02:00
while True : #run forever
if ( len ( downloadQue ) > 0 ) : #check if files ready to download
thread = Thread ( target = backgroundDownloader , args = ( downloadQue [ 0 ] , ) ) #if yes make a background task to download it
thread . start ( ) #run the background task
downloadQue . remove ( downloadQue [ 0 ] ) #remove the currently downloading file from the que
2020-04-10 20:32:49 +02:00
2020-04-10 21:00:30 +02:00
await sleep ( 1 ) #sleep 1 seccond and allo the bot to run different tasks
2020-04-10 16:39:32 +02:00
2020-04-10 20:32:49 +02:00
def backgroundDownloader ( downloadQue ) :
2020-04-10 21:00:30 +02:00
global playerQue #import the global variables
2020-04-10 20:32:49 +02:00
global fileIndex
ydl_opts = { #youtube-dl arguments
' format ' : ' worstaudio/worst ' ,
' postprocessors ' : [ {
' key ' : ' FFmpegExtractAudio ' ,
' preferredcodec ' : ' mp3 ' ,
' preferredquality ' : ' 192 ' ,
} ] ,
' outtmpl ' : str ( fileIndex ) + ' . %(ext)s ' ,
}
2020-04-10 21:00:30 +02:00
fileIndex = fileIndex + 1 #add 1 to the file index counter (used to find the mp3 files easy later and that there are no files with the same name)
with YoutubeDL ( ydl_opts ) as ydl : #download the song with the arguments from up
2020-04-10 20:32:49 +02:00
ydl . download ( [ downloadQue [ 0 ] ] )
2020-04-10 21:04:16 +02:00
playerQue . append ( str ( fileIndex - 1 ) + " .mp3 " ) #add the file to the que
2020-04-10 21:00:30 +02:00
titleQue . append ( downloadQue [ 1 ] ) #add the title to the que (for que list)
2020-04-10 16:39:32 +02:00
2020-04-10 21:00:30 +02:00
bot . loop . create_task ( checkForNextSong ( ) ) #start the music bot tasks in background
2020-04-10 16:39:32 +02:00
bot . loop . create_task ( downloadAudioFiles ( ) )
2020-04-02 18:17:24 +02:00
bot . run ( token , bot = botAccount ) #start the bot with the options in config.py