diff --git a/environment/template b/environment/template index 7d47bcc..c70b7fd 100644 --- a/environment/template +++ b/environment/template @@ -3,6 +3,7 @@ ######################## export DISCORD_BOT_TOKEN=<> +export OPENWEATHER_API_TOKEN=<> export MYSQL_HOST=<> export MYSQL_PORT=<> export MYSQL_DATABASE=<> diff --git a/requirements/common.txt b/requirements/common.txt index b2718ec..138a057 100644 --- a/requirements/common.txt +++ b/requirements/common.txt @@ -1,3 +1,5 @@ -discord.py==1.7.3 -mysqlclient==2.1.1 -SQLAlchemy==1.4.40 +discord.py +mysqlclient +SQLAlchemy +json +pyre2 \ No newline at end of file diff --git a/settings/config.py b/settings/config.py index 853cafb..10ce945 100644 --- a/settings/config.py +++ b/settings/config.py @@ -80,6 +80,14 @@ PERMISSIONS = { 'v' : ['Operador', 'BotMan'] } +OW_API_CONFIG = { + 'api_id' : os.environ.get('OPENWEATHER_API_TOKEN', 'no'), + 'gc_url' : 'http://api.openweathermap.org/geo/1.0/direct?q=,,&limit=1&appid=', + 'wh_url' : 'https://api.openweathermap.org/data/2.5/weather?lat=&lon=&units=metric&appid=' +} + +logger.dictConfig(LOGGING_CONFIG) + # Tuple of image type on image links. # e.g: https://cdn.discordapp.com/attachments/720808802340962357/988542480981061702/cat.jpeg # e.g: https://cdn.discordapp.com/attachments/720808802340962357/988542480981061702/unknow.png diff --git a/utils/commands.py b/utils/commands.py index e664ee7..46a1513 100644 --- a/utils/commands.py +++ b/utils/commands.py @@ -3,10 +3,15 @@ Bot commands. """ import logging from random import choice +import re2 from discord.ext import commands from settings.config import IMAGE_TYPES, PERMISSIONS +from utils.database import get_by_id, get_quotes, remove_quote, set_quote, count_quotes +from utils.weather import geocode, getweatherdata, displayweather + +from settings.config import PERMISSIONS, OW_API_CONFIG from utils.database import (count_quotes, get_by_id, get_quote_contains, get_quotes, remove_quote, set_quote) @@ -145,8 +150,7 @@ async def queue_stack(bot: object) -> str: return await bot.send('A list of the 5 latest message IDs follows:'\ f' `{",".join(str(q) for q in quote_id_stack[-5:])}`') - -@client.command(aliases=['cq', 'cquotes']) +@client.command(aliases=['qc', 'cquotes']) async def quote_count(bot: object) -> str: """ Outputs a quote count from the database @@ -178,11 +182,51 @@ async def info(bot: object) -> str: for lines in text: fullbanner = fullbanner + lines - msg = f'''```\n{fullbanner}\n```''' return await bot.send(msg) +@client.command(aliases=['w']) +async def weather(bot: object, *location: str) -> str: + """ + Displays the weather information for a given place + """ + if OW_API_CONFIG['api_id'] == 'no': + return await bot.send("You haven't set up an API key! Make an user and set up an API key in https://openweathermap.org/\n \ + (The weather command hansn't been set up properly, make sure you have `OPENWEATHER_API_TOKEN` set up") + if location: + location = str(location) + stripped = re2.sub(" ", "", location) # Strips all whitespace + separated = stripped.split(',') # Splits between commas + separated.pop(-1) + separated[0] = separated[0][1:len(separated[0])] # These two commands clean up input for the parser + + if len(separated) > 3: + return await bot.send("This command takes 3 parameters at most!\n \ + (Syntax: `--w , , `)") + if len(separated) == 1: + city = separated[0] + state = "" + country = "" + elif len(separated) == 2: + city = separated[0] + state = separated[1] + country = "" + else: + city = separated[0] + state = separated[1] + country = separated[2] + else: + city = "" + state = "" + country = "" + + lat, lon = geocode(city, state, country) + weatherdata = getweatherdata(lat, lon) + msg = displayweather(weatherdata) + + return await bot.send(msg) + @client.command(aliases=['qcontains', 'qsearch']) async def quote_contains(bot: object, part: str) -> str: diff --git a/utils/weather.py b/utils/weather.py new file mode 100644 index 0000000..b672cb7 --- /dev/null +++ b/utils/weather.py @@ -0,0 +1,98 @@ +import logging + +from settings.config import OW_API_CONFIG + +import urllib.request +import json +import re2 + +def geocode(city = 'curitiba', state = 'parana', country = 'BR') -> str: + """ + Converts city, state and country parameters into their coordinates + """ + if city == "" and state == "" and country == "": + city = 'curitiba' + state = 'parana' + country = 'BR' + ow_gc_url = OW_API_CONFIG['gc_url'] + ow_gc_url = re2.sub('', city, ow_gc_url) + ow_gc_url = re2.sub('', state, ow_gc_url) + ow_gc_url = re2.sub('', OW_API_CONFIG['api_id'], ow_gc_url) + + placedata = urllib.request.urlopen(ow_gc_url) + placedata = placedata.read().decode() + placedata = json.loads(str(placedata)) + + return str(placedata[0]['lat']), str(placedata[0]['lon']) + +def getweatherdata(lat, lon): + """ + Gets weather data based on coordinates + """ + ow_wh_url = OW_API_CONFIG['wh_url'] + ow_wh_url = re2.sub('', lat, ow_wh_url) + ow_wh_url = re2.sub('', lon, ow_wh_url) + ow_wh_url = re2.sub('', OW_API_CONFIG['api_id'], ow_wh_url) + + weatherdata = urllib.request.urlopen(ow_wh_url) + weatherdata = weatherdata.read().decode() + weatherdata = json.loads(str(weatherdata)) + + return weatherdata + +def displayweather(wdata): + """ + "Prettifies" the output for discord + """ + try: + wdata['weather'][0]['description'] + description = wdata['weather'][0]['description'] + except: + description = "No data on description" + try: + wdata['main']['temp'] + temp = wdata['main']['temp'] + tempmsg = f"Temperature is {temp}ºC" + except: + tempmsg = "No data on temperature" + try: + wdata['main']['feels_like'] + feels_like = wdata['main']['feels_like'] + feels_likemsg = f"Feels like {feels_like}ºC" + except: + feels_likemsg = "No data on perceived temperature" + try: + wdata['main']['humidity'] + humidity = wdata['main']['humidity'] + humiditymsg = f"Humidity is {humidity}%" + except: + humiditymsg = "No data on humidity" + try: + wdata['wind']['speed'] + wind_speed = wdata['wind']['speed'] + wind_speedmsg = f"Wind speed is {wind_speed}m/s" + except: + wind_speedmsg = "No data on wind speed" + try: + wdata['wind']['gust'] + wind_gusts = wdata['wind']['gust'] + wind_gustsmsg = f"with gusts of {wind_gusts}m/s" + except: + wind_gustsmsg = "with no data on gusts" + try: + wdata['clouds']['all'] + cloud_coverage = wdata['clouds']['all'] + cloud_coveragemsg = f"Cloud coverage is {cloud_coverage}%" + except: + cloud_coveragemsg = "No data on cloud coverage" + name = wdata['name'] + + msg = f""" + ``` + Weather for {name}: + {description}, {tempmsg}. {feels_likemsg}. {humiditymsg}. + {wind_speedmsg}, {wind_gustsmsg}. {cloud_coveragemsg}. + ```""" + + return msg \ No newline at end of file