commit be4a6e4417d27eab0b7b70df6e7e56c74a163959 Author: Jonas Leder Date: Thu Apr 2 11:40:56 2020 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..32db8b1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ + +level.db +level.db + +config.py + +__pycache__/ diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..f0242a5 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.pythonPath": "C:\\Users\\jonas\\AppData\\Local\\Programs\\Python\\Python38\\python.exe" +} \ No newline at end of file diff --git a/bot.py b/bot.py new file mode 100644 index 0000000..3934d2e --- /dev/null +++ b/bot.py @@ -0,0 +1,313 @@ +import discord +from discord.ext import commands +from discord.utils import get +from discord import FFmpegPCMAudio +from os import system +import sqlite3 +import youtube_dl +import os +from time import sleep, time +from datetime import datetime, timedelta +from config import * + +polls = {} + +bot = commands.Bot(command_prefix=prefix) + +conn = sqlite3.connect('level.db') +c = conn.cursor() + +try: + 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)" + c.execute(sql) + c.execute(sql2) + c.execute(sql3) +except: + pass + +@bot.event +async def on_ready(): + print('Logged in as') + print(bot.user.name) + print(bot.user.id) + print('------') + await bot.change_presence(activity=discord.Game(name="Discord")) + +@bot.event +async def on_message(message): + print(str(message.author) + " sent: " + str(message.content) + ", latency: " + str(bot.latency) + " ms, Bot: " + str(message.author.bot)) + if(message.author.bot) or (message.author.id == bot.user.id): + return + res = c.execute("SELECT textXP FROM MESSAGES WHERE user=? AND server = ?", [message.author.id, message.guild.id]) + result = res.fetchone() + if (result == None): + c.execute("INSERT INTO MESSAGES VALUES (?, ?, ?, 0, 0)", [message.author.id, message.guild.id, messageXP]) + messages = messageXP + else: + messages = result[0] + messageXP + c.execute("UPDATE MESSAGES SET textXP = ? WHERE user = ? AND server = ?", [messages, message.author.id, message.guild.id]) + + conn.commit() + + if message.content.startswith(prefix): + await bot.process_commands(message) + +@bot.event +async def on_raw_reaction_add(message): + if(message.user_id == bot.user.id): + return + res = c.execute("SELECT reactionXP FROM MESSAGES WHERE user=? AND server = ?", [message.user_id, message.guild_id]) + result = res.fetchone() + if (result == None): + c.execute("INSERT INTO MESSAGES VALUES (?, ?, 0, ?, 0)", [message.user_id, message.guild_id, reactionXP]) + messages = reactionXP + else: + messages = result[0] + reactionXP + c.execute("UPDATE MESSAGES SET reactionXP = ? WHERE user = ? AND server = ?", [messages, message.user_id, message.guild_id]) + + try: + polls[str(message.message_id)] + calls = c.execute("SELECT calls FROM poll WHERE pollID = ? AND reaction = ?", [message.message_id, str(message.emoji)]).fetchone()[0] + c.execute("UPDATE poll SET calls = ? WHERE pollID = ? AND reaction = ?", [calls + 1, message.message_id, str(message.emoji)]) + except: + pass + + conn.commit() + +@bot.event +async def on_raw_reaction_remove(message): + try: + polls[str(message.message_id)] + calls = c.execute("SELECT calls FROM poll WHERE pollID = ? AND reaction = ?", [message.message_id, str(message.emoji)]).fetchone()[0] + c.execute("UPDATE poll SET calls = ? WHERE pollID = ? AND reaction = ?", [calls - 1, message.message_id, str(message.emoji)]) + except: + pass + conn.commit() + +@bot.event +async def on_voice_state_update(member, before, after): + print(member.avatar_url) + if member.bot or (member.id == bot.user.id): + return + if not before.afk and after.afk: + print(str(member) + " is now AFK") + result = c.execute("SELECT startTime FROM VcActive WHERE user=?", [member.id]).fetchone()[0] + c.execute("DELETE FROM VcActive WHERE user=?", [member.id]) + xp = (time() - result) / minutesPerVcXP + result = c.execute("SELECT vcXP FROM MESSAGES WHERE user=? AND server = ?", [member.id, member.guild.id]).fetchone()[0] + c.execute("UPDATE MESSAGES SET vcXP = ? WHERE user = ? AND server = ?", [result + round(xp), member.id, member.guild.id]) + conn.commit() + return + if before.afk and not after.afk: + print(str(member) + " is active again") + c.execute("INSERT INTO VcActive VALUES (?, ?)", [member.id, round(time())]) + conn.commit() + return + if(after.channel == None): + print(str(member) + " left the Voicechat") + print(member.id) + result = c.execute("SELECT startTime FROM VcActive WHERE user = ?", [member.id]).fetchone()[0] + c.execute("DELETE FROM VcActive WHERE user=?", [member.id]) + xp = (time() - result) / 60 / minutesPerVcXP + result = c.execute("SELECT vcXP FROM MESSAGES WHERE user=? AND server = ?", [member.id, member.guild.id]).fetchone()[0] + c.execute("UPDATE MESSAGES SET vcXP = ? WHERE user = ? AND server = ?", [result + round(xp), member.id, member.guild.id]) + conn.commit() + return + elif(before.channel == None): + print(str(member) + " joined the Voicechat " + str(after.channel)) + c.execute("INSERT INTO VcActive VALUES (?, ?)", [member.id, round(time())]) + conn.commit() + return + +@bot.command(brief="shows your current XP and level") +async def level(ctx, user : str=None): + message = ctx.message + user_ = user + user = message.author + if (user_ != None): + + user_ = user_.replace("<@!", "").replace(">", "") + for members in bot.get_all_members(): + if(str(members.id) == user_): + user = members + + temp = c.execute("SELECT textXP, reactionXP, vcXP FROM MESSAGES WHERE user=? AND server = ?", [user.id, message.guild.id]).fetchone() + messages = temp[0] + reaction = temp[1] + voice = temp[2] + unsorted_ = c.execute("SELECT user, textXP, reactionXP, vcXP FROM MESSAGES WHERE server = ?", [message.guild.id]).fetchall() + unsorted = [] + for entries in unsorted_: + unsorted.append([entries[0], (entries[1] + entries[2] + entries[3])]) + + ranking = [] + lowest = unsorted[0] + + while len(unsorted) > 0: + for i in range(0, len(unsorted)): + if(unsorted[i][1] <= lowest[1]): + lowest = unsorted[i] + unsorted.remove(lowest) + ranking.append(lowest) + if(len(unsorted) > 0): + lowest = unsorted[0] + + tempXP = messages+reaction+voice + level = 0 + levelXP = 0 + while (tempXP > 0): + levelXP = base * (factor**(level)) + tempXP = tempXP - levelXP + level = level + 1 + + level = level - 1 + + for entries in reversed(ranking): + if(user.id == entries[0]): + rank = len(ranking) - ranking.index(entries) + username = str(user.name) + embed = discord.Embed(title="Stats of " + username , description="Rank " + str(rank) + " of " + str(len(ranking))) + embed.set_thumbnail(url=user.avatar_url) + embed.add_field(name="Text XP", value=messages) + embed.add_field(name="Reaction XP", value=reaction) + embed.add_field(name="Voice XP", value=voice) + embed.add_field(name="Total XP", value=messages+reaction+voice) + 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 message.channel.send(embed=embed) + +@bot.command(brief="shows the leaderboard") +async def leaderboard(ctx): + unsorted_ = c.execute("SELECT user, textXP, reactionXP, vcXP FROM MESSAGES WHERE server = ?", [ctx.message.guild.id]).fetchall() + unsorted = [] + for entries in unsorted_: + unsorted.append([entries[0], (entries[1] + entries[2] + entries[3]), entries[1], entries[2], entries[3]]) + + ranking = [] + lowest = unsorted[0] + + while len(unsorted) > 0: + for i in range(0, len(unsorted)): + if(unsorted[i][1] <= lowest[1]): + lowest = unsorted[i] + unsorted.remove(lowest) + ranking.append(lowest) + if(len(unsorted) > 0): + lowest = unsorted[0] + + message = "" + while len(ranking) > 10: + ranking.remove(ranking[0]) + + badges = [":first_place: ", ":second_place: ", ":third_place: ", ":four: ", ":five: ", ":six: ", ":seven: ", ":eight: ", ":nine: ", ":keycap_ten: "] + for entries in reversed(ranking): + message = message + badges[len(ranking) - ranking.index(entries) - 1] + ": <@" + str(entries[0]) + "> **Total:** " + str(entries[1]) + " XP (**Text:** " + str(entries[2]) + " + **Reaction:** " + str(entries[3]) + " + **VC:** " + str(entries[4]) + ")\n" + embed = discord.Embed(title="Leaderboard" , description=message) + await ctx.message.channel.send(embed=embed) + +@bot.command(pass_context=True, brief="joins your current voicechat and makes a wrong sound") +async def wrong(ctx): + channel = ctx.author.voice.channel + await channel.connect() + voice = ctx.voice_client + voice.play(discord.FFmpegPCMAudio("wrong.mp3")) + while voice.is_playing(): + sleep(0.1) + await ctx.message.guild.voice_client.disconnect() + +@bot.command(pass_context=True, brief="joins your current voicechat and makes a dock sound") +async def duck(ctx): + channel = ctx.author.voice.channel + await channel.connect() + voice = ctx.voice_client + voice.play(discord.FFmpegPCMAudio("duck.mp3")) + while voice.is_playing(): + sleep(0.1) + await ctx.message.guild.voice_client.disconnect() + +@bot.command(pass_context=True, brief="prints the ping time of the bot") +async def ping(ctx): + now = datetime.utcnow() + delta = round((now.microsecond - ctx.message.created_at.microsecond) /1000) + embed = discord.Embed(title=":ping_pong: | Pong!", description="```prolog\nLatency:: " + str(round(bot.latency * 1000)) + "ms\nResponse :: " + str(delta) + "ms```") + + await ctx.message.channel.send(embed=embed) + +@bot.command(brief="prints the text as emojies") +async def emoji(ctx, *message: str): + temp = "" + for messages in message: + temp = temp + messages + " " + messageNew = "" + for char in temp: + char = char.lower() + if char in "abcdefghijklmnopqrstuvwxyz": + messageNew = messageNew + ":regional_indicator_" + char + ":" + elif char in "1234567890": + 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 == "?": + messageNew = messageNew + ":question:" + elif char == "!": + messageNew = messageNew + ":exclamation:" + else: + messageNew = messageNew + char + await ctx.message.channel.send(messageNew) + +@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)") +async def poll(ctx, question, *options: str): + if len(options) <= 1: + options = list(options) + options.append("yes") + options.append("no") + options = tuple(options) + if len(options) > 9: + await ctx.message.channel.send('You cannot make a poll for more than 9 things!') + return + + if len(options) == 2 and options[0] == 'yes' and options[1] == 'no': + reactions = ['✅', '❌'] + else: + reactions = ['1⃣', '2⃣', '3⃣', '4⃣', '5⃣', '6⃣', '7⃣', '8⃣', '9⃣'] + + description = [] + for x, option in enumerate(options): + description += '\n {} {}'.format(reactions[x], option) + embed = discord.Embed(title=question, description=''.join(description)) + await ctx.message.channel.send("@everyone") + react_message = await ctx.message.channel.send(embed=embed) + polls[str(react_message.id)] = react_message + for reaction in reactions[:len(options)]: + c.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)) + await react_message.edit(embed=embed) + +@bot.command(pass_context=True, brief="shows the result of a poll, give the poll ID as argument") +async def result(ctx, id): + poll_message = polls[str(id)] + embed = poll_message.embeds[0] + + del polls[str(id)] + unformatted_options = [x.strip() for x in poll_message.embeds[0].description.split('\n')] + opt_dict = {x[:2]: x[3:] for x in unformatted_options} if unformatted_options[0][0] == '1' \ + else {x[:1]: x[2:] for x in unformatted_options} + result = {} + + request = c.execute("SELECT calls, reaction FROM poll WHERE pollID = ?", [id]).fetchall() + for results in request: + result[results[1]] = results[0] + + description = '\n'.join(['{} {}: {} votes'.format(key, opt_dict[key], result[key]) for key in result.keys()]) + embed = discord.Embed(title=poll_message.embeds[0].title, description=description) + embed.set_footer(text='enden on ' + datetime.now().strftime("%d.%m.%Y %H:%M:%S")) + await poll_message.edit(embed=embed) + await ctx.message.channel.send("You can find the result on the original poll: " + poll_message.jump_url) + c.execute("DELETE FROM poll where pollID = ?", [id]) + conn.commit() + +bot.run(token, bot=botAccount) \ No newline at end of file diff --git a/config_example.py b/config_example.py new file mode 100644 index 0000000..a268179 --- /dev/null +++ b/config_example.py @@ -0,0 +1,10 @@ +TOKEN = "" +botAccount = True #if you use a normal useraccount, set this to false + +prefix = "?" #This you have to enter before every command (e.g. ?help) +messageXP = 2 #The XP you get for every message +reactionXP = 1 #The XP you get for every reaction +minutesPerVcXP = 3 #The number of minutes you have to be online on the voicechat to get 1XP +#leveling settings +base = 10 +factor = 1.1 \ No newline at end of file diff --git a/database.db b/database.db new file mode 100644 index 0000000..672421a Binary files /dev/null and b/database.db differ diff --git a/duck.mp3 b/duck.mp3 new file mode 100644 index 0000000..3ea0d5e Binary files /dev/null and b/duck.mp3 differ diff --git a/wrong.mp3 b/wrong.mp3 new file mode 100644 index 0000000..07f18bf Binary files /dev/null and b/wrong.mp3 differ