diff --git a/.env_example b/.env_example index 91c8786..4a9b313 100644 --- a/.env_example +++ b/.env_example @@ -1 +1,2 @@ -DISCORD_TOKEN= \ No newline at end of file +DISCORD_TOKEN= +WEATHER_TOKEN= \ No newline at end of file diff --git a/.gitignore b/.gitignore index 03bb558..2d1a429 100644 --- a/.gitignore +++ b/.gitignore @@ -56,6 +56,7 @@ coverage.xml *.pot # Django stuff: +*.log local_settings.py db.sqlite3 db.sqlite3-journal @@ -129,3 +130,6 @@ dmypy.json todo.txt .vscode/launch.json +storage/prefixes.json +.vscode/settings.json +storage/tokens.json \ No newline at end of file diff --git a/cogs/fun.py b/cogs/fun.py index 8e1d546..1ef09ce 100644 --- a/cogs/fun.py +++ b/cogs/fun.py @@ -1,6 +1,9 @@ # Basic imports: import discord from discord.ext import commands +import json +import random +import requests # Cog class: class Fun(commands.Cog): @@ -12,12 +15,69 @@ def __init__(self, client): # This is an event: # @commands.Cog.listener() # async def on_ready(self): - # print('This will be printed to the console.') -# This is a command: @commands.command() - async def ping1(self, ctx): - await ctx.send("pong nigga") + async def react(self, ctx, emote): + if isinstance(emote, int): + emotename = client.get_emoji(emote) + if isinstance(emote, str): + emotename = discord.utils.get(self.client.emojis, name=emote) + await ctx.message.add_reaction(emotename) + + @commands.command(name="8ball") + async def _8ball(self, ctx): + import random + linenum = random.randint(1, 20) + user = "<@" + str(ctx.author.id) + ">" + with open('./storage/8ball.json') as responses: + response = json.load(responses) + await ctx.send(random.choice(response) + user) + + # Figlet command + @commands.command() + async def figlet(self, ctx, *, figtext): + from pyfiglet import Figlet + fig = Figlet() + figsend = fig.renderText(figtext) + await ctx.send(f"```{figsend}```") + + @commands.command() + async def urban(self, ctx, *, word): + url = "http://urbanscraper.herokuapp.com/define/" + completeurl = url + word + try: + response = requests.get(completeurl) + except: + ctx.send("Couldn't find that word.") + + res = response.json() + term = res["term"] + defi = res["definition"] + example = res["example"] + word_url = res["url"] + posttime = res["posted"] + author = res["author"] + + urbanembed = discord.Embed(title=term,url=word_url) + urbanembed.add_field(name="**Definition:**",value=defi) + urbanembed.add_field(name="**Example:**",value=example) + urbanembed.set_footer(text="Author: " + author) + await ctx.send(embed=urbanembed) + + + + @commands.command() + async def emote(self, ctx, search_term): + if isinstance(search_term, int): + emotename = client.get_emoji(search_term) + if isinstance(search_term, str): + emotename = discord.utils.get(self.client.emojis, name=search_term) + await ctx.send(emotename) + + @commands.command(hidden=True) + async def tts(self, ctx, *, message): + await ctx.send(content=message, tts=True) + # This always needs to be at the end of a cog file: def setup(client): diff --git a/cogs/utility.py b/cogs/utility.py index 6fa8166..7016fcb 100644 --- a/cogs/utility.py +++ b/cogs/utility.py @@ -1,6 +1,12 @@ # Basic imports: +import os import discord from discord.ext import commands +import math +import requests +import dotenv +import json +import datetime # Cog class: class Utility(commands.Cog): @@ -16,8 +22,167 @@ def __init__(self, client): # This is a command: @commands.command() - async def ping5(self, ctx): - await ctx.send("pong nigga") + async def shorten(self, ctx, url): + """Shortens a URL. Usage: ?shorten """ + import gdshortener + s = gdshortener.ISGDShortener() + await ctx.send(s.shorten(f'{url}')) + + + # Avatar command + @commands.command() + async def avatar(self, ctx): + """Sends you your avatar.""" + avi_url = ctx.author.avatar_url + aviembed = discord.Embed(title="Avatar of " + ctx.author.name, url=avi_url) + aviembed.set_image(url=avi_url) + await ctx.send(embed=aviembed) + + + # Calc command + @commands.command() + async def calc(self, ctx, n1, op, n2=0): + """Calculate a mathematical expression. Usage: ?calc """ + SUP = str.maketrans("0123456789", "⁰¹²³⁴⁵⁶⁷⁸⁹") + if op == "+": + answer = int(n1) + int(n2) + equation = f"```{n1}{op}{n2}```" + elif op == "-": + answer = int(n1) - int(n2) + equation = f"```{n1}{op}{n2}```" + elif op == "*": + answer = int(n1) * int(n2) + equation = f"```{n1}{op}{n2}```" + elif op == "/": + answer = int(n1) / int(n2) + equation = f"```{n1}{op}{n2}```" + elif op == "!" or op == "fac": + answer = str(math.factorial(int(n1))) + equation = f'```!{n1}```' + elif op == "pow": + answer = math.pow(int(n1), int(n2)) + equation = f"```{n1}" + f"{n2}".translate(SUP) + "```" + elif op == "sqrt": + answer = math.sqrt(int(n1)) + equation = f"```√{n1}```" + else: + await ctx.send("Invalid operator!") + calcembed = discord.Embed(title="Calculator", color=0x7ac5c9) + calcembed.add_field(name="Math equation:", value=equation) + calcembed.add_field(name="Answer:", value=f"```{answer}```") + await ctx.send(embed=calcembed) + + # Clear command + @commands.command() + async def purge(self, ctx, amount=0): + """Purge a specified amount of messages. Usage: ?purge """ + if amount == 0: + await ctx.send("Please provide a number.") + else: + await ctx.channel.purge(limit=amount + 1) + + # Code command + @commands.command() + async def code(self, ctx): + """Sends bot repo link.""" + await ctx.send("https://github.com/TKLprojects/travbot.py") + + # Desc command + @commands.command() + async def desc(self, ctx, *, cname): + """Changes voice channel name. Usage: ?desc """ + channel = ctx.author.voice.channel + await channel.edit(name=cname) + await ctx.send(f'Changed channel name to "{cname}"') + + # Weather command + @commands.command(name="weather") + async def _weather(self, ctx, city_name): + """Get weather information about a location. Usage: ?weather """ + with open("storage/tokens.json") as tokensfile: + tokenfile = json.load(tokensfile) + weathertoken = tokenfile['weather'] + base_url = "http://api.weatherapi.com/v1/current.json?" + complete_url = base_url + "key=" + str(weathertoken) + "&q=" + str(city_name) + try: + response = requests.get(complete_url) + except BaseException: + await ctx.send("no") + res = response.json() + # TODO #5 Fix KeyError (can't read token) + weather = res["current"] + location = res["location"] + condition = weather["condition"] + + current_temperature = str(int(weather["temp_c"])) + "°C" + current_pressure = str(weather["pressure_mb"])[-3:] + "mBar" + current_humidity = str(weather["humidity"]) + "%" + image = "https:" + str(condition["icon"]) + weather_timezone = str(location["localtime"]) + weather_location = str(location["name"]) + weather_description = "Description: " + str(condition["text"]) + weather_wind_kph = str(weather["wind_kph"]) + weather_wind_dir = str(weather["wind_dir"]) + + weatherembed = discord.Embed(title="Weather for " + weather_location,color=0x7ac5c9) + weatherembed.set_author(name=f"{self.client.user.name}",icon_url=self.client.user.avatar_url) + weatherembed.set_footer(text="https://weatherapi.com") + weatherembed.add_field(name="Temperature:", value=current_temperature) + weatherembed.add_field(name="Pressure:", value=current_pressure) + weatherembed.add_field(name="Humidity:", value=current_humidity) + weatherembed.add_field(name="Wind:",value=weather_wind_kph + " km/h " + weather_wind_dir) + weatherembed.add_field(name="Time:", value=weather_timezone) + weatherembed.set_thumbnail(url=image) + await ctx.send(embed=weatherembed) + + @commands.command() + async def reboot(self, ctx): + """Reboots the bot, if you run via pm2.""" + await ctx.send("Rebooting...") + exit() + + # Userinfo command + @commands.command() + async def userinfo(self, ctx): + """Displays info about author.""" + currentDate = datetime.datetime.now() + avi_url = ctx.author.avatar_url + infoembed = discord.Embed() + infoembed.set_author(name=ctx.author.name + "#" + ctx.author.discriminator,icon_url=avi_url) + infoembed.add_field(name="Status", value=ctx.author.status) + infoembed.add_field(name="Joined at", value=str(ctx.author.joined_at.day) + "-" + str(ctx.author.joined_at.month) + "-" + str(ctx.author.joined_at.year) + " " + str(ctx.author.joined_at.hour) + ":" + str(ctx.author.joined_at.minute)) + infoembed.add_field(name="Registered at", value=str(ctx.author.created_at.day) + "-" + str(ctx.author.created_at.month) + "-" + str(ctx.author.created_at.year) + " " + str(ctx.author.created_at.hour) + ":" + str(ctx.author.created_at.minute)) + infoembed.add_field(name="Nickname", value=ctx.author.display_name) + infoembed.set_footer(text=str(currentDate.day) + "-" + str(currentDate.month) + "-" + str(currentDate.year) + " " + str(currentDate.hour) + ":" + str(currentDate.minute) + ":" + str(currentDate.second)) + infoembed.set_thumbnail(url=avi_url) + await ctx.send(embed=infoembed) + + # Serverinfo command + @commands.command() + async def serverinfo(self, ctx): + """Displays info about the current guild.""" + serverembed = discord.Embed(title="Server info") + serverembed.add_field(name="Server Name",value=ctx.guild.name) + serverembed.add_field(name="Owner",value=ctx.guild.owner) + serverembed.add_field(name="Members",value=len(ctx.guild.members)) + serverembed.add_field(name="Channels",value=len(ctx.guild.text_channels + ctx.guild.voice_channels)) + serverembed.add_field(name="Text Channels",value=len(ctx.guild.text_channels)) + serverembed.add_field(name="Voice Channels",value=len(ctx.guild.voice_channels)) + serverembed.set_thumbnail(url=ctx.guild.icon_url) + await ctx.send(embed=serverembed) + + # Poll command + # @commands.command() + # async def poll(self, ctx, question, *options: str): + # """Display a poll""" + # import time + # pollembed = discord.Embed(description=question) + # pollembed.set_author(name=f"Poll created by {ctx.message.author}",icon_url=ctx.guild.icon_url) + # pollembed.set_footer(text="React to vote.") + # reactions = ['✅', '❌'] + # reactmessage = await ctx.send(embed=pollembed) + # for reaction in reactions: + # await ctx.message.add_reaction(reaction) # This always needs to be at the end of a cog file: def setup(client): diff --git a/main.py b/main.py index 431cecd..fbe6c2e 100644 --- a/main.py +++ b/main.py @@ -14,12 +14,6 @@ handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s')) logger.addHandler(handler) -# Dotenv -import dotenv -from dotenv import load_dotenv -load_dotenv() -token = os.getenv('DISCORD_TOKEN') - # Server specific prefixes def get_prefix(client, message): with open('./storage/prefixes.json', 'r') as f: @@ -81,5 +75,8 @@ async def cprefix(ctx, prefix): json.dump(prefixes, f, indent=4) await ctx.send(f'Prefix changed to: {prefix}') +with open("storage/tokens.json") as tokensfile: + tokenfile = json.load(tokensfile) + token = tokenfile['bot'] client.run(token) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..937da9e --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +discord.py +pyfiglet +gdshortener +urbandictionary \ No newline at end of file diff --git a/storage/8ball.json b/storage/8ball.json new file mode 100644 index 0000000..aa335de --- /dev/null +++ b/storage/8ball.json @@ -0,0 +1,22 @@ +[ + "Most likely, ", + "It is certain, ", + "It is decidedly so, ", + "Without a doubt, ", + "Definitely, ", + "You may rely on it, ", + "As I see it, yes, ", + "Outlook good, ", + "Yes, ", + "Signs point to yes, ", + "Reply hazy, try again, ", + "Ask again later, ", + "Better not tell you now, ", + "Cannot predict now, ", + "Concentrate and ask again, ", + "Don't count on it, ", + "My reply is no, ", + "My sources say no, ", + "Outlook not so good, ", + "Very doubtful, " +] \ No newline at end of file