formatting everything and adding corsa club to the trackdays command since they finally put their shit on msreg
This commit is contained in:
parent
32bf0f5275
commit
d5f6d87b92
@ -9,97 +9,115 @@ import get_from_reddit
|
||||
def get_red_panda():
|
||||
red_panda = None
|
||||
while not red_panda:
|
||||
red_panda = requests.get('https://some-random-api.ml/img/red_panda').json()['link']
|
||||
return red_panda
|
||||
red_panda = requests.get("https://some-random-api.ml/img/red_panda").json()[
|
||||
"link"
|
||||
]
|
||||
return red_panda
|
||||
|
||||
|
||||
def get_panda():
|
||||
panda = None
|
||||
while not panda:
|
||||
panda = requests.get('https://some-random-api.ml/img/panda').json()['link']
|
||||
return panda
|
||||
panda = requests.get("https://some-random-api.ml/img/panda").json()["link"]
|
||||
return panda
|
||||
|
||||
|
||||
def get_racoon():
|
||||
racoon = None
|
||||
while not racoon:
|
||||
racoon = requests.get('https://some-random-api.ml/img/racoon').json()['link']
|
||||
return racoon
|
||||
racoon = requests.get("https://some-random-api.ml/img/racoon").json()["link"]
|
||||
return racoon
|
||||
|
||||
|
||||
def get_fox():
|
||||
fox = None
|
||||
while not fox:
|
||||
fox = requests.get('https://some-random-api.ml/img/fox').json()['link']
|
||||
return fox
|
||||
fox = requests.get("https://some-random-api.ml/img/fox").json()["link"]
|
||||
return fox
|
||||
|
||||
|
||||
def get_cat():
|
||||
cat = None
|
||||
while not cat:
|
||||
cat = requests.get('https://some-random-api.ml/img/cat').json()['link']
|
||||
return cat
|
||||
cat = requests.get("https://some-random-api.ml/img/cat").json()["link"]
|
||||
return cat
|
||||
|
||||
|
||||
def get_kangaroo():
|
||||
kangaroo = None
|
||||
while not kangaroo:
|
||||
kangaroo = requests.get('https://some-random-api.ml/img/kangaroo').json()['link']
|
||||
return kangaroo
|
||||
kangaroo = requests.get("https://some-random-api.ml/img/kangaroo").json()[
|
||||
"link"
|
||||
]
|
||||
return kangaroo
|
||||
|
||||
|
||||
def get_koala():
|
||||
koala = None
|
||||
while not koala:
|
||||
koala = requests.get('https://some-random-api.ml/img/koala').json()['link']
|
||||
return koala
|
||||
koala = requests.get("https://some-random-api.ml/img/koala").json()["link"]
|
||||
return koala
|
||||
|
||||
|
||||
def get_dog():
|
||||
return random.choice([random_sheeb, random_dog, random_dog_reddit])()
|
||||
|
||||
|
||||
def get_birb():
|
||||
return random.choice([random_bird, random_bird_reddit])()
|
||||
|
||||
|
||||
def random_sheeb():
|
||||
return requests.get(
|
||||
'http://shibe.online/api/shibes?count=1&urls=true'
|
||||
).text.split('"')[1]
|
||||
return requests.get("http://shibe.online/api/shibes?count=1&urls=true").text.split(
|
||||
'"'
|
||||
)[1]
|
||||
|
||||
|
||||
def random_dog():
|
||||
dog_url = None
|
||||
while not dog_url:
|
||||
dog_url = requests.get('https://dog.ceo/api/breeds/image/random').json()['message']
|
||||
return dog_url
|
||||
dog_url = requests.get("https://dog.ceo/api/breeds/image/random").json()[
|
||||
"message"
|
||||
]
|
||||
return dog_url
|
||||
|
||||
|
||||
def random_bird():
|
||||
bird = None
|
||||
while not bird:
|
||||
bird = requests.get('https://some-random-api.ml/img/birb').json()['link']
|
||||
if 'mp4' in bird[-3:]:
|
||||
bird = requests.get("https://some-random-api.ml/img/birb").json()["link"]
|
||||
if "mp4" in bird[-3:]:
|
||||
bird = None
|
||||
return bird
|
||||
return bird
|
||||
|
||||
|
||||
def random_dog_reddit():
|
||||
return get_from_reddit.get_image(
|
||||
[
|
||||
'AustralianCattleDog',
|
||||
'GSP',
|
||||
'corgi',
|
||||
'dogpictures',
|
||||
'rarepuppers',
|
||||
'tippytaps',
|
||||
'vizsla',
|
||||
'zoomies',
|
||||
'shiba',
|
||||
"AustralianCattleDog",
|
||||
"GSP",
|
||||
"corgi",
|
||||
"dogpictures",
|
||||
"rarepuppers",
|
||||
"tippytaps",
|
||||
"vizsla",
|
||||
"zoomies",
|
||||
"shiba",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def random_bird_reddit():
|
||||
return get_from_reddit.get_image(
|
||||
[
|
||||
'birbs',
|
||||
"birbs",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def get_rat():
|
||||
return get_from_reddit.get_image('rats')
|
||||
return get_from_reddit.get_image("rats")
|
||||
|
||||
|
||||
def dale():
|
||||
return random.choice(glob.glob('/tmp/dale/*'))
|
||||
|
||||
return random.choice(glob.glob("/tmp/dale/*"))
|
||||
|
97
app/bf5.py
97
app/bf5.py
@ -1,59 +1,60 @@
|
||||
import requests, json, pprint, discord
|
||||
from bs4 import BeautifulSoup
|
||||
pp = pprint.PrettyPrinter(indent=4)
|
||||
|
||||
|
||||
def get_player(player):
|
||||
player = player.lower()
|
||||
url = "https://battlefieldtracker.com/bfv/profile/origin/" + player + "/overview"
|
||||
headers = { 'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; Win64; x64)' }
|
||||
response = requests.get(url, headers=headers).text
|
||||
soup = BeautifulSoup(response, "html.parser")
|
||||
script = soup.find_all("script")
|
||||
player = player.lower()
|
||||
url = "https://battlefieldtracker.com/bfv/profile/origin/" + player + "/overview"
|
||||
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64)"}
|
||||
response = requests.get(url, headers=headers).text
|
||||
soup = BeautifulSoup(response, "html.parser")
|
||||
script = soup.find_all("script")
|
||||
|
||||
jsonstring = str(script[1])
|
||||
jsonstring = jsonstring[33:-131]
|
||||
data = json.loads(jsonstring)
|
||||
jsonstring = str(script[1])
|
||||
jsonstring = jsonstring[33:-131]
|
||||
data = json.loads(jsonstring)
|
||||
|
||||
# Get Player Data
|
||||
origin_name = 'bfv|origin|' + player
|
||||
# Get Player Data
|
||||
origin_name = "bfv|origin|" + player
|
||||
|
||||
base_stat_blob = data['stats-v2']['standardProfiles'][origin_name]
|
||||
account_name = base_stat_blob['platformInfo']['platformUserHandle']
|
||||
avatar_url = base_stat_blob['platformInfo']['avatarUrl']
|
||||
|
||||
stats_overview = base_stat_blob['segments'][0]['stats']
|
||||
rank = stats_overview['rank']
|
||||
rank_title = rank['metadata']['label']
|
||||
rank_number = rank['displayValue']
|
||||
base_stat_blob = data["stats-v2"]["standardProfiles"][origin_name]
|
||||
account_name = base_stat_blob["platformInfo"]["platformUserHandle"]
|
||||
avatar_url = base_stat_blob["platformInfo"]["avatarUrl"]
|
||||
|
||||
# Build the embed
|
||||
embed = discord.Embed(description='-------', color=15105570, type="rich")
|
||||
embed.set_thumbnail(url=avatar_url)
|
||||
embed.set_author(name="Battlefield V stats for %s" % account_name)
|
||||
embed.add_field(name="**Rank**", value="%s, %s" % (rank_number, rank_title), inline=False)
|
||||
stats_overview = base_stat_blob["segments"][0]["stats"]
|
||||
rank = stats_overview["rank"]
|
||||
rank_title = rank["metadata"]["label"]
|
||||
rank_number = rank["displayValue"]
|
||||
|
||||
gameplay_stats = [
|
||||
'scorePerMinute',
|
||||
'kdRatio',
|
||||
'assists',
|
||||
'shotsAccuracy',
|
||||
'killStreak',
|
||||
'dogtagsTaken',
|
||||
'headshots',
|
||||
'longestHeadshot',
|
||||
'heals',
|
||||
'revives',
|
||||
'revivesRecieved',
|
||||
'resupplies',
|
||||
'aceSquad',
|
||||
'wlPercentage',
|
||||
]
|
||||
# Build the embed
|
||||
embed = discord.Embed(description="-------", color=15105570, type="rich")
|
||||
embed.set_thumbnail(url=avatar_url)
|
||||
embed.set_author(name="Battlefield V stats for %s" % account_name)
|
||||
embed.add_field(
|
||||
name="**Rank**", value="%s, %s" % (rank_number, rank_title), inline=False
|
||||
)
|
||||
|
||||
for stat in gameplay_stats:
|
||||
embed.add_field(name="**%s**" % stats_overview[stat]['displayName'], value=stats_overview[stat]['displayValue'], inline=True)
|
||||
# embed.add_field(name='Raw value', value=stats_overview[stat]['displayValue'], inline=True)
|
||||
# embed.add_field(name='Global Percentile', value=stats_overview[stat]['percentile'], inline=True)
|
||||
return embed
|
||||
gameplay_stats = [
|
||||
"scorePerMinute",
|
||||
"kdRatio",
|
||||
"assists",
|
||||
"shotsAccuracy",
|
||||
"killStreak",
|
||||
"dogtagsTaken",
|
||||
"headshots",
|
||||
"longestHeadshot",
|
||||
"heals",
|
||||
"revives",
|
||||
"revivesRecieved",
|
||||
"resupplies",
|
||||
"aceSquad",
|
||||
"wlPercentage",
|
||||
]
|
||||
|
||||
# assault_stats = base_stat_blob['segments'][9]
|
||||
# medic_stats = base_stat_blob['segments'][10]
|
||||
for stat in gameplay_stats:
|
||||
embed.add_field(
|
||||
name="**%s**" % stats_overview[stat]["displayName"],
|
||||
value=stats_overview[stat]["displayValue"],
|
||||
inline=True,
|
||||
)
|
||||
return embed
|
||||
|
980
app/bot.py
980
app/bot.py
File diff suppressed because it is too large
Load Diff
@ -1,15 +1,22 @@
|
||||
import requests
|
||||
|
||||
|
||||
def download_image(url, path=None):
|
||||
|
||||
request = requests.get(url)
|
||||
suffix_list = ['jpeg', 'jpg', 'png', 'tif', 'svg',]
|
||||
extension = request.headers['content-type'].split('/')[1]
|
||||
suffix_list = [
|
||||
"jpeg",
|
||||
"jpg",
|
||||
"png",
|
||||
"tif",
|
||||
"svg",
|
||||
]
|
||||
extension = request.headers["content-type"].split("/")[1]
|
||||
|
||||
if not path:
|
||||
path = "/tmp/image.{}".format(extension)
|
||||
|
||||
if extension in suffix_list:
|
||||
open(path, 'wb').write(requests.get(url).content)
|
||||
open(path, "wb").write(requests.get(url).content)
|
||||
return path
|
||||
return 'Invalid image format'
|
||||
return "Invalid image format"
|
||||
|
157
app/corona.py
157
app/corona.py
@ -8,75 +8,113 @@ import requests
|
||||
import string
|
||||
import datetime
|
||||
|
||||
|
||||
def get_csv():
|
||||
git_url = 'https://api.github.com/repos/CSSEGISandData/COVID-19/contents/csse_covid_19_data/csse_covid_19_daily_reports'
|
||||
git_blob = requests.get(git_url).json()
|
||||
git_url = "https://api.github.com/repos/CSSEGISandData/COVID-19/contents/csse_covid_19_data/csse_covid_19_daily_reports"
|
||||
git_blob = requests.get(git_url).json()
|
||||
|
||||
today = datetime.datetime.utcnow().date()
|
||||
todays_date = today.strftime('%m-%d-%Y')
|
||||
yesterday = today - datetime.timedelta(days=1)
|
||||
yesterdays_date = yesterday.strftime('%m-%d-%Y')
|
||||
today = datetime.datetime.utcnow().date()
|
||||
todays_date = today.strftime("%m-%d-%Y")
|
||||
yesterday = today - datetime.timedelta(days=1)
|
||||
yesterdays_date = yesterday.strftime("%m-%d-%Y")
|
||||
|
||||
most_recent = next(filter(lambda x: yesterdays_date in x['name'], git_blob))
|
||||
file_name = most_recent['name']
|
||||
download_url = most_recent['download_url']
|
||||
most_recent_csv = "/app/%s" % file_name
|
||||
if not os.path.exists(most_recent_csv):
|
||||
print("no local csv found, downloading %s" % file_name)
|
||||
r = requests.get(download_url, allow_redirects=True)
|
||||
open(most_recent_csv, 'wb').write(r.content)
|
||||
most_recent = next(filter(lambda x: yesterdays_date in x["name"], git_blob))
|
||||
file_name = most_recent["name"]
|
||||
download_url = most_recent["download_url"]
|
||||
most_recent_csv = "/app/%s" % file_name
|
||||
if not os.path.exists(most_recent_csv):
|
||||
print("no local csv found, downloading %s" % file_name)
|
||||
r = requests.get(download_url, allow_redirects=True)
|
||||
open(most_recent_csv, "wb").write(r.content)
|
||||
|
||||
two_days_ago = today - datetime.timedelta(days=2)
|
||||
two_days_ago_date = two_days_ago.strftime('%m-%d-%Y')
|
||||
yesterday_object = next(filter(lambda x: two_days_ago_date in x['name'], git_blob))
|
||||
yesterday_filename = yesterday_object['name']
|
||||
yesterday_url = yesterday_object['download_url']
|
||||
yesterday_csv = "/app/%s" % yesterday_filename
|
||||
two_days_ago = today - datetime.timedelta(days=2)
|
||||
two_days_ago_date = two_days_ago.strftime("%m-%d-%Y")
|
||||
yesterday_object = next(filter(lambda x: two_days_ago_date in x["name"], git_blob))
|
||||
yesterday_filename = yesterday_object["name"]
|
||||
yesterday_url = yesterday_object["download_url"]
|
||||
yesterday_csv = "/app/%s" % yesterday_filename
|
||||
|
||||
if not os.path.exists(yesterday_csv):
|
||||
print("no local csv found, downloading %s" % yesterday_filename)
|
||||
r = requests.get(yesterday_url, allow_redirects=True)
|
||||
open(yesterday_csv, 'wb').write(r.content)
|
||||
if not os.path.exists(yesterday_csv):
|
||||
print("no local csv found, downloading %s" % yesterday_filename)
|
||||
r = requests.get(yesterday_url, allow_redirects=True)
|
||||
open(yesterday_csv, "wb").write(r.content)
|
||||
|
||||
return most_recent_csv, yesterday_csv
|
||||
return most_recent_csv, yesterday_csv
|
||||
|
||||
|
||||
def query_csv(csv_path, location):
|
||||
series = read_csv(csv_path, header=0, parse_dates=[0], index_col=0, squeeze=True)
|
||||
last_updated = series['Last_Update'].iloc[0]
|
||||
location_query = series.loc[series['Province_State'] == location]
|
||||
if location_query.empty:
|
||||
location_query = series.loc[series['Country_Region'] == location]
|
||||
series = read_csv(csv_path, header=0, parse_dates=[0], index_col=0, squeeze=True)
|
||||
last_updated = series["Last_Update"].iloc[0]
|
||||
location_query = series.loc[series["Province_State"] == location]
|
||||
if location_query.empty:
|
||||
embed = discord.Embed(description="No results found for %s.\n\nPlease enter a valid Country name or US state" % location, color=0x428bca, type="rich")
|
||||
embed.set_author(name="CSSE at Johns Hopkins University", icon_url='https://www.pngitem.com/pimgs/m/27-270528_johns-hopkins-was-a-founding-member-of-the.png')
|
||||
return embed
|
||||
return last_updated, location_query.sum()
|
||||
location_query = series.loc[series["Country_Region"] == location]
|
||||
if location_query.empty:
|
||||
embed = discord.Embed(
|
||||
description="No results found for %s.\n\nPlease enter a valid Country name or US state"
|
||||
% location,
|
||||
color=0x428BCA,
|
||||
type="rich",
|
||||
)
|
||||
embed.set_author(
|
||||
name="CSSE at Johns Hopkins University",
|
||||
icon_url="https://www.pngitem.com/pimgs/m/27-270528_johns-hopkins-was-a-founding-member-of-the.png",
|
||||
)
|
||||
return embed
|
||||
return last_updated, location_query.sum()
|
||||
|
||||
|
||||
def sum_numbers(location):
|
||||
today, yesterday = get_csv()
|
||||
try:
|
||||
last_updated, yesterday_sum = query_csv(yesterday, location)
|
||||
last_updated, today_sum = query_csv(today, location)
|
||||
except TypeError:
|
||||
return discord.Embed(description="No data for %s. Did you make a typo?" % location, color=0x428bca, type="rich")
|
||||
today, yesterday = get_csv()
|
||||
try:
|
||||
last_updated, yesterday_sum = query_csv(yesterday, location)
|
||||
last_updated, today_sum = query_csv(today, location)
|
||||
except TypeError:
|
||||
return discord.Embed(
|
||||
description="No data for %s. Did you make a typo?" % location,
|
||||
color=0x428BCA,
|
||||
type="rich",
|
||||
)
|
||||
|
||||
confirmed = "%s (+%s from yesterday)" % (
|
||||
today_sum["Confirmed"],
|
||||
int(today_sum["Confirmed"]) - int(yesterday_sum["Confirmed"]),
|
||||
)
|
||||
deaths = "%s (+%s from yesterday)" % (
|
||||
today_sum["Deaths"],
|
||||
int(today_sum["Deaths"]) - int(yesterday_sum["Deaths"]),
|
||||
)
|
||||
recovered = "%s (+%s from yesterday)" % (
|
||||
today_sum["Recovered"],
|
||||
int(today_sum["Recovered"]) - int(yesterday_sum["Recovered"]),
|
||||
)
|
||||
|
||||
confirmed = "%s (+%s from yesterday)" % (today_sum['Confirmed'], int(today_sum['Confirmed']) - int(yesterday_sum['Confirmed']))
|
||||
deaths = "%s (+%s from yesterday)" % (today_sum['Deaths'], int(today_sum['Deaths']) - int(yesterday_sum['Deaths']))
|
||||
recovered = "%s (+%s from yesterday)" % (today_sum['Recovered'], int(today_sum['Recovered']) - int(yesterday_sum['Recovered']))
|
||||
embed = discord.Embed(
|
||||
description="Most recent Covid19 stats for %s\nUpdated once a day\n(Last update was %s)"
|
||||
% (location, last_updated),
|
||||
color=0x428BCA,
|
||||
type="rich",
|
||||
)
|
||||
embed.set_author(
|
||||
name="CSSE at Johns Hopkins University",
|
||||
icon_url="https://www.pngitem.com/pimgs/m/27-270528_johns-hopkins-was-a-founding-member-of-the.png",
|
||||
)
|
||||
embed.add_field(
|
||||
name=":rotating_light: Confirmed Cases :rotating_light:",
|
||||
value=confirmed,
|
||||
inline=False,
|
||||
)
|
||||
embed.add_field(
|
||||
name=":hospital: Recovered Cases :hospital:", value=recovered, inline=False
|
||||
)
|
||||
embed.add_field(
|
||||
name=":skull_crossbones: Deaths :skull_crossbones:", value=deaths, inline=False
|
||||
)
|
||||
# if 'Not available' not in get_vaccination_data(location):
|
||||
# embed.add_field(name=':sparkles: :syringe: Percent vaccinated :syringe: :sparkles:', value=get_vaccination_data(location) + "\nVaccination numbers pulled from\nhttps://covidvaxcount.live", inline=False)
|
||||
embed.add_field(name="Source", value="https://github.com/CSSEGISandData/COVID-19")
|
||||
|
||||
embed = discord.Embed(description="Most recent Covid19 stats for %s\nUpdated once a day\n(Last update was %s)" % (location, last_updated), color=0x428bca, type="rich")
|
||||
embed.set_author(name="CSSE at Johns Hopkins University", icon_url='https://www.pngitem.com/pimgs/m/27-270528_johns-hopkins-was-a-founding-member-of-the.png')
|
||||
embed.add_field(name=':rotating_light: Confirmed Cases :rotating_light:', value=confirmed, inline=False)
|
||||
embed.add_field(name=':hospital: Recovered Cases :hospital:', value=recovered, inline=False)
|
||||
embed.add_field(name=':skull_crossbones: Deaths :skull_crossbones:', value=deaths, inline=False)
|
||||
# if 'Not available' not in get_vaccination_data(location):
|
||||
# embed.add_field(name=':sparkles: :syringe: Percent vaccinated :syringe: :sparkles:', value=get_vaccination_data(location) + "\nVaccination numbers pulled from\nhttps://covidvaxcount.live", inline=False)
|
||||
embed.add_field(name='Source', value="https://github.com/CSSEGISandData/COVID-19")
|
||||
return embed
|
||||
|
||||
return embed
|
||||
|
||||
# def get_vaccination_data(location):
|
||||
# url = requests.get('https://covidvaxcount.live')
|
||||
@ -98,11 +136,12 @@ def sum_numbers(location):
|
||||
# return "Not available for %s" % location
|
||||
# return percent_vaccinated
|
||||
|
||||
|
||||
def parse_message(message):
|
||||
try:
|
||||
state = string.capwords(' '.join(message.lstrip('!corona').split()))
|
||||
if not state:
|
||||
state = 'California'
|
||||
except IndexError:
|
||||
state = 'California'
|
||||
return sum_numbers(state)
|
||||
try:
|
||||
state = string.capwords(" ".join(message.lstrip("!corona").split()))
|
||||
if not state:
|
||||
state = "California"
|
||||
except IndexError:
|
||||
state = "California"
|
||||
return sum_numbers(state)
|
||||
|
@ -1,10 +1,11 @@
|
||||
import random
|
||||
import help_methods
|
||||
|
||||
|
||||
def decide(message):
|
||||
choices = message.replace('!decide', '' ).lstrip().split(' or ')
|
||||
if '' in choices:
|
||||
return help_methods.get_help_message('decide')
|
||||
choices = message.replace("!decide", "").lstrip().split(" or ")
|
||||
if "" in choices:
|
||||
return help_methods.get_help_message("decide")
|
||||
elif len(choices) > 1:
|
||||
return random.choice(choices)
|
||||
else:
|
||||
|
@ -14,24 +14,32 @@ def get_definition(content):
|
||||
word = content.split()[1:]
|
||||
try:
|
||||
definition = requests.get(
|
||||
"https://api.urbandictionary.com/v0/define?term={}".format('%20'.join(word))
|
||||
).json()['list'][0]['definition']
|
||||
site = 'Urban Dictionary'
|
||||
"https://api.urbandictionary.com/v0/define?term={}".format(
|
||||
"%20".join(word)
|
||||
)
|
||||
).json()["list"][0]["definition"]
|
||||
site = "Urban Dictionary"
|
||||
|
||||
except IndexError:
|
||||
try:
|
||||
# Try another dictionary
|
||||
definition = requests.get(
|
||||
"http://api.pearson.com/v2/dictionaries/ldoce5/entries?headword={}".format('%20'.join(word))
|
||||
).json()['results'][0]['senses'][0]['definition'][0]
|
||||
"http://api.pearson.com/v2/dictionaries/ldoce5/entries?headword={}".format(
|
||||
"%20".join(word)
|
||||
)
|
||||
).json()["results"][0]["senses"][0]["definition"][0]
|
||||
|
||||
site = 'Pearson'
|
||||
site = "Pearson"
|
||||
except IndexError:
|
||||
definition = 'No definition found'
|
||||
definition = "No definition found"
|
||||
|
||||
embed = discord.Embed(description="%s:\n%s" % (' '.join(word), definition), color=0x428bca, type="rich")
|
||||
embed = discord.Embed(
|
||||
description="%s:\n%s" % (" ".join(word), definition),
|
||||
color=0x428BCA,
|
||||
type="rich",
|
||||
)
|
||||
embed.set_author(name="From %s" % site)
|
||||
|
||||
return embed
|
||||
|
||||
return help_methods.get_help_message('define')
|
||||
return help_methods.get_help_message("define")
|
||||
|
72
app/dice.py
72
app/dice.py
@ -1,39 +1,53 @@
|
||||
import discord
|
||||
from random import randint
|
||||
|
||||
|
||||
def roll_logic(sides):
|
||||
return randint(1, sides)
|
||||
return randint(1, sides)
|
||||
|
||||
|
||||
def roll(number_of_die, sides, number_to_add=None):
|
||||
results = list(tuple(roll_logic(int(sides)) for _ in range(int(number_of_die))))
|
||||
results = list(tuple(roll_logic(int(sides)) for _ in range(int(number_of_die))))
|
||||
|
||||
# blue
|
||||
embed_color = 3447003
|
||||
if sum(results) == 1:
|
||||
# Red
|
||||
embed_color = 15158332
|
||||
if sum(results) >= 10:
|
||||
# Green
|
||||
embed_color = 3066993
|
||||
if sum(results) >= 15:
|
||||
# Gold
|
||||
embed_color = 15844367
|
||||
# blue
|
||||
embed_color = 3447003
|
||||
if sum(results) == 1:
|
||||
# Red
|
||||
embed_color = 15158332
|
||||
if sum(results) >= 10:
|
||||
# Green
|
||||
embed_color = 3066993
|
||||
if sum(results) >= 15:
|
||||
# Gold
|
||||
embed_color = 15844367
|
||||
|
||||
embed = discord.Embed(description=None, color=embed_color, type="rich")
|
||||
embed.set_author(name="Rolling %s %s sided die" % (number_of_die, sides))
|
||||
embed.add_field(name="Rolls", value=results, inline=False)
|
||||
if number_to_add:
|
||||
embed.add_field(
|
||||
name="**Total**",
|
||||
value=":game_die: %s+%s = %s"
|
||||
% (sum(results), number_to_add, (sum(results) + number_to_add)),
|
||||
inline=False,
|
||||
)
|
||||
else:
|
||||
embed.add_field(
|
||||
name="**Total**", value=":game_die: %s" % sum(results), inline=False
|
||||
)
|
||||
return embed
|
||||
|
||||
embed = discord.Embed(description=None, color=embed_color, type="rich")
|
||||
embed.set_author(name="Rolling %s %s sided die" % (number_of_die, sides))
|
||||
embed.add_field(name='Rolls', value=results, inline=False)
|
||||
if number_to_add:
|
||||
embed.add_field(name="**Total**", value=":game_die: %s+%s = %s" % (sum(results), number_to_add, (sum(results) + number_to_add)), inline=False)
|
||||
else:
|
||||
embed.add_field(name="**Total**", value=":game_die: %s" % sum(results), inline=False)
|
||||
return embed
|
||||
|
||||
def parse_message(message):
|
||||
message = ' '.join(message.split()[1:])
|
||||
if '+' in message:
|
||||
try:
|
||||
number_to_add = int(message.split('+')[-1])
|
||||
return roll(message.split('d')[0], message.split('d')[1].split('+')[0], number_to_add)
|
||||
except ValueError:
|
||||
return "Could not add that number to the total roll"
|
||||
return roll(message.split('d')[0], message.split('d')[1])
|
||||
message = " ".join(message.split()[1:])
|
||||
if "+" in message:
|
||||
try:
|
||||
number_to_add = int(message.split("+")[-1])
|
||||
return roll(
|
||||
message.split("d")[0],
|
||||
message.split("d")[1].split("+")[0],
|
||||
number_to_add,
|
||||
)
|
||||
except ValueError:
|
||||
return "Could not add that number to the total roll"
|
||||
return roll(message.split("d")[0], message.split("d")[1])
|
||||
|
@ -3,6 +3,7 @@ import sys
|
||||
|
||||
import help_methods
|
||||
|
||||
|
||||
def check_8ball(question):
|
||||
"""
|
||||
check_8ball(question)
|
||||
@ -14,37 +15,35 @@ def check_8ball(question):
|
||||
question = question.split()[1:]
|
||||
|
||||
positive_responses = [
|
||||
'As I see it, yes',
|
||||
'It is certain',
|
||||
'It is decidedly so',
|
||||
'Most likely',
|
||||
'Oh for sure brother',
|
||||
'Outlook good',
|
||||
'Signs point to yes',
|
||||
'Without a doubt',
|
||||
'Yes, definitely',
|
||||
'Yes',
|
||||
'You can count on it',
|
||||
"As I see it, yes",
|
||||
"It is certain",
|
||||
"It is decidedly so",
|
||||
"Most likely",
|
||||
"Oh for sure brother",
|
||||
"Outlook good",
|
||||
"Signs point to yes",
|
||||
"Without a doubt",
|
||||
"Yes, definitely",
|
||||
"Yes",
|
||||
"You can count on it",
|
||||
]
|
||||
negative_responses = [
|
||||
'Dont count on it',
|
||||
'My sources say no',
|
||||
'My thoughts are.....no',
|
||||
'Outlook not so good',
|
||||
'Very doubtful',
|
||||
"Dont count on it",
|
||||
"My sources say no",
|
||||
"My thoughts are.....no",
|
||||
"Outlook not so good",
|
||||
"Very doubtful",
|
||||
]
|
||||
noncommittal_responses = [
|
||||
'Ask again later',
|
||||
'Better not tell you now',
|
||||
'Can\'t answer that right now',
|
||||
'Concentrate and ask again',
|
||||
'Reply hazy try again',
|
||||
"Ask again later",
|
||||
"Better not tell you now",
|
||||
"Can't answer that right now",
|
||||
"Concentrate and ask again",
|
||||
"Reply hazy try again",
|
||||
]
|
||||
|
||||
return random.choice(
|
||||
positive_responses +
|
||||
negative_responses +
|
||||
noncommittal_responses
|
||||
positive_responses + negative_responses + noncommittal_responses
|
||||
)
|
||||
|
||||
return help_methods.get_help_message('8ball')
|
||||
return help_methods.get_help_message("8ball")
|
||||
|
@ -1,8 +1,13 @@
|
||||
from bs4 import BeautifulSoup
|
||||
import requests
|
||||
|
||||
def get_excuse():
|
||||
url = requests.get('http://www.devexcuses.com')
|
||||
soup = BeautifulSoup(url.content, features="html.parser")
|
||||
|
||||
return "```{}```".format(str(soup.find("p", {"class": "excuse"}).contents[0]).split(">")[1].split("</a")[0])
|
||||
def get_excuse():
|
||||
url = requests.get("http://www.devexcuses.com")
|
||||
soup = BeautifulSoup(url.content, features="html.parser")
|
||||
|
||||
return "```{}```".format(
|
||||
str(soup.find("p", {"class": "excuse"}).contents[0])
|
||||
.split(">")[1]
|
||||
.split("</a")[0]
|
||||
)
|
||||
|
183
app/ffxiv.py
183
app/ffxiv.py
@ -2,94 +2,113 @@ import requests
|
||||
import os
|
||||
import discord
|
||||
|
||||
if os.getenv('ffxiv_token'):
|
||||
token = "&private_key=%s" % os.getenv('ffxiv_token')
|
||||
if os.getenv("ffxiv_token"):
|
||||
token = "&private_key=%s" % os.getenv("ffxiv_token")
|
||||
else:
|
||||
token = ''
|
||||
token = ""
|
||||
|
||||
|
||||
def parse_message(message):
|
||||
name = message.split()[1] + '+' + message.split()[2]
|
||||
server = message.split()[3]
|
||||
name = message.split()[1] + "+" + message.split()[2]
|
||||
server = message.split()[3]
|
||||
|
||||
return make_request(name=name, server=server)
|
||||
return make_request(name=name, server=server)
|
||||
|
||||
|
||||
def make_request(name, server):
|
||||
player_search = "https://xivapi.com/character/search?name=%s&server=%s%s" % (name, server, token)
|
||||
# print(player_search)
|
||||
player_id = list(filter(
|
||||
lambda x: server.lower() in x['Server'].lower(),
|
||||
requests.get(player_search).json()['Results']
|
||||
))[0]['ID']
|
||||
import pprint
|
||||
pp = pprint.PrettyPrinter(indent=2, compact=True)
|
||||
|
||||
# if adding extended=1 to the query, you'll see some image files, eg. /cj/1/blackmage.png
|
||||
# prepend these with https://xivapi.com/ to get a useable url
|
||||
# https://xivapi.com//cj/1/blackmage.png
|
||||
request_url = "https://xivapi.com/character/%s?extended=1&data=CJ,FC%s" % (player_id, token)
|
||||
# print(request_url)
|
||||
player_blob = requests.get(request_url).json()
|
||||
character = player_blob['Character']
|
||||
# pp.pprint(player_blob)
|
||||
# pp.pprint(character)
|
||||
|
||||
current_class = character['ActiveClassJob']
|
||||
current_class_name = current_class['Job']['Name']
|
||||
current_class_level = character['ActiveClassJob']['Level']
|
||||
xp_to_level_up = current_class['ExpLevelTogo']
|
||||
job_icon = "https://xivapi.com/%s" % current_class['Job']['Icon']
|
||||
|
||||
if character['GrandCompany']['Company']:
|
||||
grand_company = character['GrandCompany']
|
||||
|
||||
if player_blob['FreeCompany']:
|
||||
free_company = player_blob['FreeCompany']
|
||||
fc_member_count = free_company['ActiveMemberCount']
|
||||
fc_name = free_company['Name']
|
||||
fc_slogan = free_company['Slogan']
|
||||
fc_tag = free_company['Tag']
|
||||
fc_rank = free_company['Rank']
|
||||
fc_estate = free_company['Estate']
|
||||
fc_plot = fc_estate['Plot']
|
||||
|
||||
|
||||
embed = discord.Embed(description=character['Name'], color=0x428bca, type="rich")
|
||||
embed.set_author(name="FFXIV API bullshit for %s\nPlayer ID: %s" % (character['Name'], character['ID']), icon_url="http://na.lodestonenews.com/images/thumbnail.png")
|
||||
embed.set_thumbnail(url=job_icon)
|
||||
embed.add_field(name="Current Class", value="%s - Lvl: %s" % (current_class_name, current_class_level), inline=True)
|
||||
embed.add_field(name="XP to level up", value=xp_to_level_up, inline=True)
|
||||
embed.add_field(name="Race", value=character['Race']['Name'], inline=True)
|
||||
if character['GrandCompany']['Company']:
|
||||
embed.add_field(
|
||||
name="Grand Company",
|
||||
value="%s of the %s" % (
|
||||
grand_company['Rank']['Name'],
|
||||
grand_company['Company']['Name']),
|
||||
inline=False
|
||||
)
|
||||
else:
|
||||
embed.add_field(name="Grand Company", value="Not in a Grand Company", inline=False)
|
||||
if player_blob['FreeCompany']:
|
||||
embed.add_field(
|
||||
name="Free Company: %s (%s)" % (fc_name, fc_tag),
|
||||
value="\nActive Members: %s\nFC Rank: %s\nFC Estate: %s" % (
|
||||
fc_member_count, fc_rank, fc_plot
|
||||
),
|
||||
inline=False
|
||||
)
|
||||
else:
|
||||
embed.add_field(name="Free Company", value="Not in a Free Company", inline=False)
|
||||
|
||||
embed.set_image(url=character['Portrait'])
|
||||
embed.add_field(name="All other classes", value="-----", inline=False)
|
||||
all_classes = character['ClassJobs']
|
||||
for job in all_classes:
|
||||
job_icon = "https://xivapi.com%s" % job['Job']['Icon']
|
||||
embed.add_field(
|
||||
name=job['Job']['Abbreviation'],
|
||||
value=job['Level'], inline=True
|
||||
player_search = "https://xivapi.com/character/search?name=%s&server=%s%s" % (
|
||||
name,
|
||||
server,
|
||||
token,
|
||||
)
|
||||
# print(player_search)
|
||||
player_id = list(
|
||||
filter(
|
||||
lambda x: server.lower() in x["Server"].lower(),
|
||||
requests.get(player_search).json()["Results"],
|
||||
)
|
||||
)[0]["ID"]
|
||||
import pprint
|
||||
|
||||
#embed.set_footer(text='Feel free to use my refer a friend code: P9CQ9JUT')
|
||||
return embed
|
||||
pp = pprint.PrettyPrinter(indent=2, compact=True)
|
||||
|
||||
# if adding extended=1 to the query, you'll see some image files, eg. /cj/1/blackmage.png
|
||||
# prepend these with https://xivapi.com/ to get a useable url
|
||||
# https://xivapi.com//cj/1/blackmage.png
|
||||
request_url = "https://xivapi.com/character/%s?extended=1&data=CJ,FC%s" % (
|
||||
player_id,
|
||||
token,
|
||||
)
|
||||
# print(request_url)
|
||||
player_blob = requests.get(request_url).json()
|
||||
character = player_blob["Character"]
|
||||
# pp.pprint(player_blob)
|
||||
# pp.pprint(character)
|
||||
|
||||
current_class = character["ActiveClassJob"]
|
||||
current_class_name = current_class["Job"]["Name"]
|
||||
current_class_level = character["ActiveClassJob"]["Level"]
|
||||
xp_to_level_up = current_class["ExpLevelTogo"]
|
||||
job_icon = "https://xivapi.com/%s" % current_class["Job"]["Icon"]
|
||||
|
||||
if character["GrandCompany"]["Company"]:
|
||||
grand_company = character["GrandCompany"]
|
||||
|
||||
if player_blob["FreeCompany"]:
|
||||
free_company = player_blob["FreeCompany"]
|
||||
fc_member_count = free_company["ActiveMemberCount"]
|
||||
fc_name = free_company["Name"]
|
||||
fc_slogan = free_company["Slogan"]
|
||||
fc_tag = free_company["Tag"]
|
||||
fc_rank = free_company["Rank"]
|
||||
fc_estate = free_company["Estate"]
|
||||
fc_plot = fc_estate["Plot"]
|
||||
|
||||
embed = discord.Embed(description=character["Name"], color=0x428BCA, type="rich")
|
||||
embed.set_author(
|
||||
name="FFXIV API bullshit for %s\nPlayer ID: %s"
|
||||
% (character["Name"], character["ID"]),
|
||||
icon_url="http://na.lodestonenews.com/images/thumbnail.png",
|
||||
)
|
||||
embed.set_thumbnail(url=job_icon)
|
||||
embed.add_field(
|
||||
name="Current Class",
|
||||
value="%s - Lvl: %s" % (current_class_name, current_class_level),
|
||||
inline=True,
|
||||
)
|
||||
embed.add_field(name="XP to level up", value=xp_to_level_up, inline=True)
|
||||
embed.add_field(name="Race", value=character["Race"]["Name"], inline=True)
|
||||
if character["GrandCompany"]["Company"]:
|
||||
embed.add_field(
|
||||
name="Grand Company",
|
||||
value="%s of the %s"
|
||||
% (grand_company["Rank"]["Name"], grand_company["Company"]["Name"]),
|
||||
inline=False,
|
||||
)
|
||||
else:
|
||||
embed.add_field(
|
||||
name="Grand Company", value="Not in a Grand Company", inline=False
|
||||
)
|
||||
if player_blob["FreeCompany"]:
|
||||
embed.add_field(
|
||||
name="Free Company: %s (%s)" % (fc_name, fc_tag),
|
||||
value="\nActive Members: %s\nFC Rank: %s\nFC Estate: %s"
|
||||
% (fc_member_count, fc_rank, fc_plot),
|
||||
inline=False,
|
||||
)
|
||||
else:
|
||||
embed.add_field(
|
||||
name="Free Company", value="Not in a Free Company", inline=False
|
||||
)
|
||||
|
||||
embed.set_image(url=character["Portrait"])
|
||||
embed.add_field(name="All other classes", value="-----", inline=False)
|
||||
all_classes = character["ClassJobs"]
|
||||
for job in all_classes:
|
||||
job_icon = "https://xivapi.com%s" % job["Job"]["Icon"]
|
||||
embed.add_field(
|
||||
name=job["Job"]["Abbreviation"], value=job["Level"], inline=True
|
||||
)
|
||||
|
||||
# embed.set_footer(text='Feel free to use my refer a friend code: P9CQ9JUT')
|
||||
return embed
|
||||
|
@ -2,6 +2,7 @@ import random
|
||||
import string
|
||||
import requests
|
||||
|
||||
|
||||
def get_image(boards, nsfw=False):
|
||||
"""
|
||||
get_image(boards, nsfw=False)
|
||||
@ -14,36 +15,34 @@ def get_image(boards, nsfw=False):
|
||||
boards = random.choice(boards)
|
||||
|
||||
domains = [
|
||||
'cdn.awwni.m',
|
||||
'gfycat.com',
|
||||
'i.imgur.com',
|
||||
'i.redd.it',
|
||||
'i.reddituploads.com',
|
||||
'i3.kym-cdn.com',
|
||||
'imgur.com',
|
||||
'media.giphy.com',
|
||||
"cdn.awwni.m",
|
||||
"gfycat.com",
|
||||
"i.imgur.com",
|
||||
"i.redd.it",
|
||||
"i.reddituploads.com",
|
||||
"i3.kym-cdn.com",
|
||||
"imgur.com",
|
||||
"media.giphy.com",
|
||||
]
|
||||
request_string = "https://reddit.com/r/{}/random.json".format(boards)
|
||||
|
||||
if not nsfw:
|
||||
# Append this header to the request. Tells the API to only return SFW results
|
||||
request_string += '?obey_over18=true'
|
||||
request_string += "?obey_over18=true"
|
||||
|
||||
# Spoof our user agent with each request so we dont get rate limited
|
||||
random_user_agent = ''.join(
|
||||
random.SystemRandom().choice(
|
||||
string.ascii_uppercase + string.digits
|
||||
) for _ in range(5)
|
||||
random_user_agent = "".join(
|
||||
random.SystemRandom().choice(string.ascii_uppercase + string.digits)
|
||||
for _ in range(5)
|
||||
)
|
||||
|
||||
response = requests.get(
|
||||
request_string,
|
||||
headers = {'User-agent':random_user_agent}
|
||||
).json()[0]['data']['children'][0]
|
||||
request_string, headers={"User-agent": random_user_agent}
|
||||
).json()[0]["data"]["children"][0]
|
||||
|
||||
if response['data']['domain'] not in domains:
|
||||
if response["data"]["domain"] not in domains:
|
||||
# If we dont find an approved domain, re-try the request
|
||||
return get_image(boards, nsfw=nsfw)
|
||||
image_url = response['data']['url'].replace('http://', 'https://')
|
||||
image_url = response["data"]["url"].replace("http://", "https://")
|
||||
|
||||
return image_url
|
||||
|
@ -7,35 +7,28 @@ import role_check
|
||||
|
||||
def create_issue(title, description):
|
||||
|
||||
post_args = {
|
||||
'title': title,
|
||||
'description': description
|
||||
}
|
||||
post_args = {"title": title, "description": description}
|
||||
|
||||
headers = {
|
||||
'PRIVATE-TOKEN': os.getenv('gitlab_token')
|
||||
}
|
||||
headers = {"PRIVATE-TOKEN": os.getenv("gitlab_token")}
|
||||
|
||||
r = requests.post(
|
||||
'https://git.luker.gq/api/v4/projects/1/issues',
|
||||
data=post_args,
|
||||
headers=headers
|
||||
"https://git.luker.gq/api/v4/projects/1/issues", data=post_args, headers=headers
|
||||
)
|
||||
|
||||
return(r.json()['web_url'])
|
||||
return r.json()["web_url"]
|
||||
|
||||
|
||||
def parse_message(message):
|
||||
if len(message.content.split()) == 1:
|
||||
return help_methods.get_help_message(method='issue')
|
||||
return help_methods.get_help_message(method="issue")
|
||||
|
||||
try:
|
||||
message = ' '.join(message.content.split()[1:])
|
||||
title, description = message.split(';')
|
||||
message = " ".join(message.content.split()[1:])
|
||||
title, description = message.split(";")
|
||||
except Exception:
|
||||
return help_methods.get_help_message(method='issue')
|
||||
return help_methods.get_help_message(method="issue")
|
||||
|
||||
try:
|
||||
return create_issue(title=title, description=description)
|
||||
except Exception:
|
||||
return help_methods.get_help_message(method='issue')
|
||||
return help_methods.get_help_message(method="issue")
|
||||
|
@ -1,4 +1,6 @@
|
||||
import discord
|
||||
|
||||
|
||||
def get_help_message(method):
|
||||
"""
|
||||
get_help_message(method)
|
||||
@ -9,187 +11,160 @@ def get_help_message(method):
|
||||
"""
|
||||
|
||||
supported_methods = {
|
||||
'8ball': [
|
||||
'Ask dale bot a question and it will give you an 8ball response',
|
||||
'\nUsage: !8ball Will I win the lottery tomorrow?'
|
||||
],
|
||||
'ask': [
|
||||
'Submits your query to wolfram alpha. If that cannot be answered, tries wikipedia\n',
|
||||
'\nUsage: !ask 100lbs to KG'
|
||||
],
|
||||
'avatar': [
|
||||
'Returns the avatar for the mentioned user',
|
||||
'\nUsage: !avatar @somebody'
|
||||
],
|
||||
'birb': [
|
||||
'Returns a random bird photo',
|
||||
'\nUsage: !birb'
|
||||
],
|
||||
'bf5': [
|
||||
'Returns some API stats about a battlefield 5 character',
|
||||
'\nUsage: !bf5 <your origin account name>'
|
||||
],
|
||||
'dale': [
|
||||
'Posts a photo or video of Dale, the goodest boy.',
|
||||
'\nUsage: !dale'
|
||||
],
|
||||
'redpanda': [
|
||||
'Returns a random red panda photo',
|
||||
'\nUsage: !redpanda'
|
||||
],
|
||||
'panda': [
|
||||
'Returns a random panda photo',
|
||||
'\nUsage: !panda'
|
||||
],
|
||||
'koala': [
|
||||
'Returns a random koala photo',
|
||||
'\nUsage: !koala'
|
||||
],
|
||||
'clap': [
|
||||
'Returns the shittiest meme created by sassy girls on twitter this century',
|
||||
'Usage: !clap some text to be meme\'mt'
|
||||
],
|
||||
'simp': [
|
||||
'Returns a license to be a simp',
|
||||
'Usage: !simp https://some.photo.jpg'
|
||||
],
|
||||
'horny': [
|
||||
'Returns a license to be horny',
|
||||
'Usage: !horny https://some.photo.jpg'
|
||||
],
|
||||
'wasted': [
|
||||
'Overlays the GTAV wasted text over the image you link',
|
||||
'Usage: !wasted https://some.photo.jpg'
|
||||
],
|
||||
'cleanup': [
|
||||
'Admin use only. Deletes dale bot\'s messages from the channel',
|
||||
'Usage: !cleanup'
|
||||
],
|
||||
'corona': [
|
||||
'Pulls the latest corona virus stats per state from Johns Hopkins data',
|
||||
'Usage: !corona <some US state>\neg: !corona Colorado'
|
||||
],
|
||||
'decide': [
|
||||
'dale-bot will help make the tough decisions for you',
|
||||
' If there is only one option, it will give you a yes or no',
|
||||
'\nUsage: !decide cake or pie\n!decide should I do my homework'
|
||||
],
|
||||
'ffxiv': [
|
||||
'Pulls a characters data from the lodestone API\n',
|
||||
'Usage: !ffxiv <First name> <last name> <server>\n',
|
||||
'eg: !ffxiv Slamsong Bardley Adamantoise\n\n',
|
||||
'Did you know that the critically acclaimed MMORPG Final Fantasy XIV has a free trial,\n',
|
||||
'and includes the entirety of A Realm Reborn AND the award-winning Heavensward expansion\n',
|
||||
'up to level 60 with no restrictions on playtime? Sign up, and enjoy Eorzea today!'
|
||||
],
|
||||
'define': [
|
||||
'Returns a definiton of a word from urban dictionary',
|
||||
'\nUsage: !define loli'
|
||||
],
|
||||
'dog': [
|
||||
'Returns the URL to a G O O D B O Y E or G I R L',
|
||||
'\nUsage: !dog'
|
||||
],
|
||||
'emoji': [
|
||||
'Uploads the passed in URL to the server as an emoji.',
|
||||
'\nDiscord does not support GIFS. It will throw an error if you try.'
|
||||
'\nUsage: !emoji http://pictures.com/some_image.png my_new_emoji\n',
|
||||
'or `!emoji del some_emoji` to delete'
|
||||
],
|
||||
'excuse': [
|
||||
'Generates a random excuse you can give your boss',
|
||||
'\nUsage: !excuse'
|
||||
],
|
||||
'greentext': [
|
||||
'Grabs a greentext story from redditchat so you can laugh at the misfortune of others',
|
||||
'\nUsage: !greentext'
|
||||
],
|
||||
'help': [
|
||||
'Shows you this message'
|
||||
],
|
||||
'homepage': [
|
||||
'This function now outputs the SWEET-ASS picture of the day.',
|
||||
' Note this picture only changes once a day.',
|
||||
'\nUsage: !homepage'
|
||||
],
|
||||
'invite': [
|
||||
'Generates a one time use invite to the voice channel you are currently in.\n',
|
||||
'if you are not in a voice channel, the invite will be for whatever channel !invite was typed in.\n'
|
||||
'You can also specify if you want it to be a temporary invite by adding `temp` to the end\n',
|
||||
'Usage: !invite or !invite temp'
|
||||
],
|
||||
'issue': [
|
||||
'Creates an issue on gitlab with the passed in parameters\n',
|
||||
'Usage: !issue <issue title>; <issue description>',
|
||||
],
|
||||
'icon': [
|
||||
'Returns the server\'s icon URL\n',
|
||||
'Usage: !icon',
|
||||
],
|
||||
'info': [
|
||||
'Returns a blurb with information about the discord server\n',
|
||||
'Usage: !info',
|
||||
],
|
||||
'lewd': [
|
||||
'Returns a URL for a lewd image.',
|
||||
'Can only be used in NSFW channels.',
|
||||
'\nUsage: !lewd'
|
||||
],
|
||||
'purge': [
|
||||
'By default, will delete your last 20 messages. You can override this',
|
||||
' with your own number. \nUsage: !purge or !purge 15'
|
||||
],
|
||||
'roles': [
|
||||
'dale bot will PM you a message with all the roles you have on the server'
|
||||
],
|
||||
'wallpaper': [
|
||||
'Returns the URL for a 4k wallpaper. You can enter',
|
||||
'a search term as well. Supports multiple search terms as well',
|
||||
'\nUsage: !wallpaper flowers or !wallpaper mountain flowers sky '
|
||||
],
|
||||
'message': [
|
||||
'You can ask me a question directly and I will do my best to answer it.',
|
||||
'\nUsage: @dale-bot what is the capital of France?'
|
||||
],
|
||||
'meme': [
|
||||
'Generates a meme on the fly!',
|
||||
'\nExamples of all templates can be seen here https://memegen.link/examples'
|
||||
'\n\nUsage: !meme doge top text; bottom text'
|
||||
],
|
||||
'nft': [
|
||||
'Polls opensea and gets a random monkey from bored ape yacht club',
|
||||
'\nUsage: !nft'
|
||||
],
|
||||
'owo': [
|
||||
'Returns some fucky wucky text\n',
|
||||
'Usage: !owo what the fuck did you just fucking say about me you little shit?'
|
||||
],
|
||||
'pout': [
|
||||
'Returns the URL for an anime girl pouting you filthy weeb\n',
|
||||
'Usage: !pout'
|
||||
],
|
||||
'rat': [
|
||||
'Returns a random rat photo',
|
||||
'\nUsage: !rat'
|
||||
],
|
||||
'roll': [
|
||||
'Rolls N number of Y sided die\n',
|
||||
'Usage: !roll 3d20\n',
|
||||
'You can also add a modifier on the end with a +',
|
||||
'Usage: !roll 2d20+5'
|
||||
],
|
||||
'smug': [
|
||||
'Returns the URL for smug anime girl'
|
||||
],
|
||||
'source': [
|
||||
"Links you to the git repo with dale-bot's source code"
|
||||
],
|
||||
'stock': [
|
||||
'Returns basic stock information for the stock you entered.',
|
||||
'\nUsage: !stock AAPL TSLA'
|
||||
],
|
||||
'trackdays': [
|
||||
'Returns the track schedule for the tracks we frequent (buttonwillow and thunderhill).\n',
|
||||
"8ball": [
|
||||
"Ask dale bot a question and it will give you an 8ball response",
|
||||
"\nUsage: !8ball Will I win the lottery tomorrow?",
|
||||
],
|
||||
"ask": [
|
||||
"Submits your query to wolfram alpha. If that cannot be answered, tries wikipedia\n",
|
||||
"\nUsage: !ask 100lbs to KG",
|
||||
],
|
||||
"avatar": [
|
||||
"Returns the avatar for the mentioned user",
|
||||
"\nUsage: !avatar @somebody",
|
||||
],
|
||||
"birb": ["Returns a random bird photo", "\nUsage: !birb"],
|
||||
"bf5": [
|
||||
"Returns some API stats about a battlefield 5 character",
|
||||
"\nUsage: !bf5 <your origin account name>",
|
||||
],
|
||||
"dale": ["Posts a photo or video of Dale, the goodest boy.", "\nUsage: !dale"],
|
||||
"redpanda": ["Returns a random red panda photo", "\nUsage: !redpanda"],
|
||||
"panda": ["Returns a random panda photo", "\nUsage: !panda"],
|
||||
"koala": ["Returns a random koala photo", "\nUsage: !koala"],
|
||||
"clap": [
|
||||
"Returns the shittiest meme created by sassy girls on twitter this century",
|
||||
"Usage: !clap some text to be meme'mt",
|
||||
],
|
||||
"simp": [
|
||||
"Returns a license to be a simp",
|
||||
"Usage: !simp https://some.photo.jpg",
|
||||
],
|
||||
"horny": [
|
||||
"Returns a license to be horny",
|
||||
"Usage: !horny https://some.photo.jpg",
|
||||
],
|
||||
"wasted": [
|
||||
"Overlays the GTAV wasted text over the image you link",
|
||||
"Usage: !wasted https://some.photo.jpg",
|
||||
],
|
||||
"cleanup": [
|
||||
"Admin use only. Deletes dale bot's messages from the channel",
|
||||
"Usage: !cleanup",
|
||||
],
|
||||
"corona": [
|
||||
"Pulls the latest corona virus stats per state from Johns Hopkins data",
|
||||
"Usage: !corona <some US state>\neg: !corona Colorado",
|
||||
],
|
||||
"decide": [
|
||||
"dale-bot will help make the tough decisions for you",
|
||||
" If there is only one option, it will give you a yes or no",
|
||||
"\nUsage: !decide cake or pie\n!decide should I do my homework",
|
||||
],
|
||||
"ffxiv": [
|
||||
"Pulls a characters data from the lodestone API\n",
|
||||
"Usage: !ffxiv <First name> <last name> <server>\n",
|
||||
"eg: !ffxiv Slamsong Bardley Adamantoise\n\n",
|
||||
"Did you know that the critically acclaimed MMORPG Final Fantasy XIV has a free trial,\n",
|
||||
"and includes the entirety of A Realm Reborn AND the award-winning Heavensward expansion\n",
|
||||
"up to level 60 with no restrictions on playtime? Sign up, and enjoy Eorzea today!",
|
||||
],
|
||||
"define": [
|
||||
"Returns a definiton of a word from urban dictionary",
|
||||
"\nUsage: !define loli",
|
||||
],
|
||||
"dog": ["Returns the URL to a G O O D B O Y E or G I R L", "\nUsage: !dog"],
|
||||
"emoji": [
|
||||
"Uploads the passed in URL to the server as an emoji.",
|
||||
"\nDiscord does not support GIFS. It will throw an error if you try."
|
||||
"\nUsage: !emoji http://pictures.com/some_image.png my_new_emoji\n",
|
||||
"or `!emoji del some_emoji` to delete",
|
||||
],
|
||||
"excuse": [
|
||||
"Generates a random excuse you can give your boss",
|
||||
"\nUsage: !excuse",
|
||||
],
|
||||
"greentext": [
|
||||
"Grabs a greentext story from redditchat so you can laugh at the misfortune of others",
|
||||
"\nUsage: !greentext",
|
||||
],
|
||||
"help": ["Shows you this message"],
|
||||
"homepage": [
|
||||
"This function now outputs the SWEET-ASS picture of the day.",
|
||||
" Note this picture only changes once a day.",
|
||||
"\nUsage: !homepage",
|
||||
],
|
||||
"invite": [
|
||||
"Generates a one time use invite to the voice channel you are currently in.\n",
|
||||
"if you are not in a voice channel, the invite will be for whatever channel !invite was typed in.\n"
|
||||
"You can also specify if you want it to be a temporary invite by adding `temp` to the end\n",
|
||||
"Usage: !invite or !invite temp",
|
||||
],
|
||||
"issue": [
|
||||
"Creates an issue on gitlab with the passed in parameters\n",
|
||||
"Usage: !issue <issue title>; <issue description>",
|
||||
],
|
||||
"icon": [
|
||||
"Returns the server's icon URL\n",
|
||||
"Usage: !icon",
|
||||
],
|
||||
"info": [
|
||||
"Returns a blurb with information about the discord server\n",
|
||||
"Usage: !info",
|
||||
],
|
||||
"lewd": [
|
||||
"Returns a URL for a lewd image.",
|
||||
"Can only be used in NSFW channels.",
|
||||
"\nUsage: !lewd",
|
||||
],
|
||||
"purge": [
|
||||
"By default, will delete your last 20 messages. You can override this",
|
||||
" with your own number. \nUsage: !purge or !purge 15",
|
||||
],
|
||||
"roles": [
|
||||
"dale bot will PM you a message with all the roles you have on the server"
|
||||
],
|
||||
"wallpaper": [
|
||||
"Returns the URL for a 4k wallpaper. You can enter",
|
||||
"a search term as well. Supports multiple search terms as well",
|
||||
"\nUsage: !wallpaper flowers or !wallpaper mountain flowers sky ",
|
||||
],
|
||||
"message": [
|
||||
"You can ask me a question directly and I will do my best to answer it.",
|
||||
"\nUsage: @dale-bot what is the capital of France?",
|
||||
],
|
||||
"meme": [
|
||||
"Generates a meme on the fly!",
|
||||
"\nExamples of all templates can be seen here https://memegen.link/examples"
|
||||
"\n\nUsage: !meme doge top text; bottom text",
|
||||
],
|
||||
"nft": [
|
||||
"Polls opensea and gets a random monkey from bored ape yacht club",
|
||||
"\nUsage: !nft",
|
||||
],
|
||||
"owo": [
|
||||
"Returns some fucky wucky text\n",
|
||||
"Usage: !owo what the fuck did you just fucking say about me you little shit?",
|
||||
],
|
||||
"pout": [
|
||||
"Returns the URL for an anime girl pouting you filthy weeb\n",
|
||||
"Usage: !pout",
|
||||
],
|
||||
"rat": ["Returns a random rat photo", "\nUsage: !rat"],
|
||||
"roll": [
|
||||
"Rolls N number of Y sided die\n",
|
||||
"Usage: !roll 3d20\n",
|
||||
"You can also add a modifier on the end with a +",
|
||||
"Usage: !roll 2d20+5",
|
||||
],
|
||||
"smug": ["Returns the URL for smug anime girl"],
|
||||
"source": ["Links you to the git repo with dale-bot's source code"],
|
||||
"stock": [
|
||||
"Returns basic stock information for the stock you entered.",
|
||||
"\nUsage: !stock AAPL TSLA",
|
||||
],
|
||||
"trackdays": [
|
||||
"Returns the track schedule for the tracks we frequent (buttonwillow and thunderhill).\n",
|
||||
# 'Use abbreviations to reference the tracks, as follows\n',
|
||||
# 'bw = Buttonwillow Raceway\n',
|
||||
# 'willow = Willow Springs\n',
|
||||
@ -198,57 +173,110 @@ def get_help_message(method):
|
||||
# 'thill = Thunderhill Raceway Park\n',
|
||||
# 'sonoma = Sonoma Raceway\n',
|
||||
# 'acs = Auto Club Speedway\n',
|
||||
'Usage: !trackdays'
|
||||
],
|
||||
'tts': [
|
||||
'Uploads a file with the specified text as an MP3.\nThis is advanced shitposting',
|
||||
'\nUsage: !tts who watches the watchmen?',
|
||||
'\nTo list all languages, you can type `!tts langs`'
|
||||
],
|
||||
'youtube': [
|
||||
'Searches youtube for the query string and returns the first result',
|
||||
'\nUsage: !youtube sick bmx tricks'
|
||||
],
|
||||
'wink': [
|
||||
'returns a anime girl winking at you',
|
||||
'\nUsage: !wink'
|
||||
],
|
||||
'verify': [
|
||||
'Adds the twitter blue check mark to the previous message\n',
|
||||
'\nLiterally thats all it does\n'
|
||||
'\nUsage: !verify'
|
||||
],
|
||||
"Usage: !trackdays",
|
||||
],
|
||||
"tts": [
|
||||
"Uploads a file with the specified text as an MP3.\nThis is advanced shitposting",
|
||||
"\nUsage: !tts who watches the watchmen?",
|
||||
"\nTo list all languages, you can type `!tts langs`",
|
||||
],
|
||||
"youtube": [
|
||||
"Searches youtube for the query string and returns the first result",
|
||||
"\nUsage: !youtube sick bmx tricks",
|
||||
],
|
||||
"wink": ["returns a anime girl winking at you", "\nUsage: !wink"],
|
||||
"verify": [
|
||||
"Adds the twitter blue check mark to the previous message\n",
|
||||
"\nLiterally thats all it does\n" "\nUsage: !verify",
|
||||
],
|
||||
}
|
||||
|
||||
return "```css\n{}: {}\n```".format(method, ' '.join(supported_methods[method]))
|
||||
return "```css\n{}: {}\n```".format(method, " ".join(supported_methods[method]))
|
||||
|
||||
|
||||
def get_help_embed(bot):
|
||||
categories = {
|
||||
'fun': ['nft', 'bf5', 'ffxiv', 'clap', 'youtube', 'excuse', 'greentext', 'lewd', 'message', 'meme', 'homepage', 'pout', 'roll', 'smug', 'owo', 'wink', 'verify', 'horny', 'wasted', 'simp', 'trackdays'],
|
||||
'util': ['ask', 'corona', 'emoji', '8ball', 'decide', 'info', 'icon', 'wallpaper', 'stock', 'tts', 'issue'],
|
||||
'users': ['help', 'invite', 'purge', 'roles', 'source'],
|
||||
'pictures of animals': ['birb', 'redpanda', 'dale', 'dog', 'rat', 'koala', 'panda', 'raccoon', 'fox', 'cat', 'kangaroo'],
|
||||
'admin': ['cleanup']
|
||||
"fun": [
|
||||
"nft",
|
||||
"bf5",
|
||||
"ffxiv",
|
||||
"clap",
|
||||
"youtube",
|
||||
"excuse",
|
||||
"greentext",
|
||||
"lewd",
|
||||
"message",
|
||||
"meme",
|
||||
"homepage",
|
||||
"pout",
|
||||
"roll",
|
||||
"smug",
|
||||
"owo",
|
||||
"wink",
|
||||
"verify",
|
||||
"horny",
|
||||
"wasted",
|
||||
"simp",
|
||||
"trackdays",
|
||||
],
|
||||
"util": [
|
||||
"ask",
|
||||
"corona",
|
||||
"emoji",
|
||||
"8ball",
|
||||
"decide",
|
||||
"info",
|
||||
"icon",
|
||||
"wallpaper",
|
||||
"stock",
|
||||
"tts",
|
||||
"issue",
|
||||
],
|
||||
"users": ["help", "invite", "purge", "roles", "source"],
|
||||
"pictures of animals": [
|
||||
"birb",
|
||||
"redpanda",
|
||||
"dale",
|
||||
"dog",
|
||||
"rat",
|
||||
"koala",
|
||||
"panda",
|
||||
"raccoon",
|
||||
"fox",
|
||||
"cat",
|
||||
"kangaroo",
|
||||
],
|
||||
"admin": ["cleanup"],
|
||||
}
|
||||
|
||||
description = "\nBelow you can see all the commands I know.\n\n**Have a nice day!**"
|
||||
embed = discord.Embed(description=description, color=0x428bca, type="rich")
|
||||
embed.set_author(name="Hello! I'm {}".format(bot.user.name), icon_url=bot.user.default_avatar_url)
|
||||
embed = discord.Embed(description=description, color=0x428BCA, type="rich")
|
||||
embed.set_author(
|
||||
name="Hello! I'm {}".format(bot.user.name), icon_url=bot.user.default_avatar_url
|
||||
)
|
||||
|
||||
for category in categories:
|
||||
command_list = []
|
||||
for command in categories[category]:
|
||||
command_list.append("`{}`".format(command))
|
||||
embed.add_field(name="**%s**" % str(category).upper(), value=', '.join(command_list), inline=False)
|
||||
embed.add_field(
|
||||
name="**%s**" % str(category).upper(),
|
||||
value=", ".join(command_list),
|
||||
inline=False,
|
||||
)
|
||||
|
||||
description2 = "**Use `!help <Command>` for more information about a command.** \n\n" + \
|
||||
"**Examples:** \n `!help dog` for detailed help for the dog command \n\n" + \
|
||||
"**Useful links:** [My source code](https://git.luker.gq/ldooks/dragon-bot), [Donate](https://cash.me/$ldooks) \n\n" + \
|
||||
"**Invite me to another server:** [Click here](https://discord.com/oauth2/authorize?client_id=%s&scope=bot&permissions=8)" % bot.user.id
|
||||
description2 = (
|
||||
"**Use `!help <Command>` for more information about a command.** \n\n"
|
||||
+ "**Examples:** \n `!help dog` for detailed help for the dog command \n\n"
|
||||
+ "**Useful links:** [My source code](https://git.luker.gq/ldooks/dragon-bot), [Donate](https://cash.me/$ldooks) \n\n"
|
||||
+ "**Invite me to another server:** [Click here](https://discord.com/oauth2/authorize?client_id=%s&scope=bot&permissions=8)"
|
||||
% bot.user.id
|
||||
)
|
||||
|
||||
embed.add_field(name="\u200b", value=description2, inline=False)
|
||||
return embed
|
||||
|
||||
|
||||
def parse_message(message):
|
||||
method = message.split()[1]
|
||||
try:
|
||||
|
78
app/lewds.py
78
app/lewds.py
@ -12,31 +12,25 @@ def get_from_danbooru(boards, nsfw=True):
|
||||
"""
|
||||
|
||||
request = requests.get(
|
||||
'https://danbooru.donmai.us/posts/random.json?tags=rating%3Aexplicit'
|
||||
"https://danbooru.donmai.us/posts/random.json?tags=rating%3Aexplicit"
|
||||
).json()
|
||||
|
||||
# List of tags we dont want images from
|
||||
undesired_tags = [
|
||||
'bestiality',
|
||||
'pee',
|
||||
'futa',
|
||||
'futanari',
|
||||
'yaoi'
|
||||
]
|
||||
undesired_tags = ["bestiality", "pee", "futa", "futanari", "yaoi"]
|
||||
# If any undesired tags show up in the request, try again
|
||||
if not set(request['tag_string'].split()).isdisjoint(undesired_tags):
|
||||
if not set(request["tag_string"].split()).isdisjoint(undesired_tags):
|
||||
return get_from_danbooru(boards)
|
||||
|
||||
# Return the large firl url if available
|
||||
if 'large_file_url' in request.keys():
|
||||
if request['large_file_url'].startswith('/data/'):
|
||||
return "https://danbooru.donmai.us{}".format(request['large_file_url'])
|
||||
return request['large_file_url']
|
||||
if "large_file_url" in request.keys():
|
||||
if request["large_file_url"].startswith("/data/"):
|
||||
return "https://danbooru.donmai.us{}".format(request["large_file_url"])
|
||||
return request["large_file_url"]
|
||||
|
||||
if 'file_url' in request.keys():
|
||||
if request['file_url'].startswith('/data/'):
|
||||
return "https://danbooru.donmai.us{}".format(request['file_url'])
|
||||
return request['file_url']
|
||||
if "file_url" in request.keys():
|
||||
if request["file_url"].startswith("/data/"):
|
||||
return "https://danbooru.donmai.us{}".format(request["file_url"])
|
||||
return request["file_url"]
|
||||
|
||||
return get_from_danbooru(boards)
|
||||
|
||||
@ -51,30 +45,32 @@ def get_lewd():
|
||||
"""
|
||||
# List of subreddits that have the lewds we seek
|
||||
boards = [
|
||||
'2Booty',
|
||||
'ahegao',
|
||||
'bakunyuu_hentai',
|
||||
'BigAnimeTiddies',
|
||||
'hentaibreeding',
|
||||
'hentaiclevage',
|
||||
'oppailove',
|
||||
'ecchi',
|
||||
'fitdrawngirls',
|
||||
'musclegirlart',
|
||||
'fitmoe',
|
||||
'hentai',
|
||||
'rule34',
|
||||
'rule34lol',
|
||||
'WesternHentai',
|
||||
'doujinshi',
|
||||
'hentai_gif',
|
||||
'muchihentai',
|
||||
'Paizuri',
|
||||
'chiisaihentai',
|
||||
'dekaihentai',
|
||||
'WaifusGonewild',
|
||||
'thighdeology'
|
||||
"2Booty",
|
||||
"ahegao",
|
||||
"bakunyuu_hentai",
|
||||
"BigAnimeTiddies",
|
||||
"hentaibreeding",
|
||||
"hentaiclevage",
|
||||
"oppailove",
|
||||
"ecchi",
|
||||
"fitdrawngirls",
|
||||
"musclegirlart",
|
||||
"fitmoe",
|
||||
"hentai",
|
||||
"rule34",
|
||||
"rule34lol",
|
||||
"WesternHentai",
|
||||
"doujinshi",
|
||||
"hentai_gif",
|
||||
"muchihentai",
|
||||
"Paizuri",
|
||||
"chiisaihentai",
|
||||
"dekaihentai",
|
||||
"WaifusGonewild",
|
||||
"thighdeology",
|
||||
]
|
||||
|
||||
# This is really bad practice but pass boards to get_from_reddit AND danbooru so it doesnt error
|
||||
return random.choice([get_from_reddit.get_image, get_from_danbooru])(boards=boards, nsfw=True)
|
||||
return random.choice([get_from_reddit.get_image, get_from_danbooru])(
|
||||
boards=boards, nsfw=True
|
||||
)
|
||||
|
@ -3,19 +3,36 @@ import requests
|
||||
|
||||
import help_methods
|
||||
|
||||
supported_templates = sorted(list(map(lambda x: x['id'], requests.get('https://api.memegen.link/templates/').json())))
|
||||
supported_templates = sorted(
|
||||
list(
|
||||
map(
|
||||
lambda x: x["id"],
|
||||
requests.get("https://api.memegen.link/templates/").json(),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def parse_message(message):
|
||||
if len(message.split()) <= 2:
|
||||
return get_meme_help()
|
||||
|
||||
escaped_chars = {'_' : '__', ' ' : '_', '-' : '--', '?' : '~q', '%' : '~p', '#' : '~h', '/' : '~s', '\'\'' : '\"'}
|
||||
escaped_chars = {
|
||||
"_": "__",
|
||||
" ": "_",
|
||||
"-": "--",
|
||||
"?": "~q",
|
||||
"%": "~p",
|
||||
"#": "~h",
|
||||
"/": "~s",
|
||||
"''": '"',
|
||||
}
|
||||
|
||||
# Unwrap message from discord
|
||||
template = message.split()[1]
|
||||
text = message.replace('!meme {}'.format(template), '').lstrip().split(',')
|
||||
upper = text[0].split(';')[0].lstrip()
|
||||
lower = text[0].split(';')[1].lstrip()
|
||||
text = message.replace("!meme {}".format(template), "").lstrip().split(",")
|
||||
upper = text[0].split(";")[0].lstrip()
|
||||
lower = text[0].split(";")[1].lstrip()
|
||||
|
||||
# Escape special characters in upper/lower text
|
||||
for char, escaped in escaped_chars.items():
|
||||
@ -23,27 +40,30 @@ def parse_message(message):
|
||||
lower = lower.replace(char, escaped)
|
||||
|
||||
usesTemplate = True
|
||||
if template.startswith('http'):
|
||||
if template.startswith("http"):
|
||||
usesTemplate = False
|
||||
elif template not in supported_templates:
|
||||
return 'Template not supported!'
|
||||
return "Template not supported!"
|
||||
|
||||
return get_meme_url(template, upper, lower, usesTemplate)
|
||||
|
||||
|
||||
def get_meme_url(template, upper, lower, usesTemplate):
|
||||
#TODO: Implement format as a parameter?
|
||||
base_URL = 'https://memegen.link'
|
||||
custom_URL = '{}/custom'.format(base_URL)
|
||||
default_format = 'jpg'
|
||||
# TODO: Implement format as a parameter?
|
||||
base_URL = "https://memegen.link"
|
||||
custom_URL = "{}/custom".format(base_URL)
|
||||
default_format = "jpg"
|
||||
|
||||
# Generate meme url
|
||||
meme = '{}/{}/{}.{}?alt={}'.format(custom_URL, upper, lower, default_format, template)
|
||||
meme = "{}/{}/{}.{}?alt={}".format(
|
||||
custom_URL, upper, lower, default_format, template
|
||||
)
|
||||
if usesTemplate:
|
||||
meme = '{}/{}/{}/{}.{}'.format(base_URL, template, upper, lower, default_format)
|
||||
meme = "{}/{}/{}/{}.{}".format(base_URL, template, upper, lower, default_format)
|
||||
return meme
|
||||
|
||||
|
||||
def get_meme_help():
|
||||
return "{}\nYou must supply a valid template for the meme. Templates are one of the following: \n```{}```".format(
|
||||
help_methods.get_help_message('meme'),
|
||||
', '.join(supported_templates)
|
||||
return "{}\nYou must supply a valid template for the meme. Templates are one of the following: \n```{}```".format(
|
||||
help_methods.get_help_message("meme"), ", ".join(supported_templates)
|
||||
)
|
||||
|
@ -3,7 +3,7 @@ import random
|
||||
|
||||
|
||||
def get_nft():
|
||||
url = "https://api.opensea.io/api/v1/bundles?limit=50&asset_contract_address=0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d"
|
||||
x = requests.get(url).json()['bundles']
|
||||
url = "https://api.opensea.io/api/v1/bundles?limit=50&asset_contract_address=0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d"
|
||||
x = requests.get(url).json()["bundles"]
|
||||
|
||||
return random.choice(x)['assets'][0]['image_url']
|
||||
return random.choice(x)["assets"][0]["image_url"]
|
||||
|
429
app/quake.py
429
app/quake.py
@ -3,255 +3,294 @@ import requests
|
||||
import discord
|
||||
import help_methods
|
||||
|
||||
base_url = 'https://stats.quake.com/api/v2/'
|
||||
base_url = "https://stats.quake.com/api/v2/"
|
||||
|
||||
|
||||
def parse_message(message):
|
||||
"""
|
||||
parse_message(message)
|
||||
"""
|
||||
parse_message(message)
|
||||
|
||||
Handles the message and looks for the player's name.
|
||||
"""
|
||||
# Return the player's name
|
||||
name = message.content.split()[1]
|
||||
if len(message.content.split()) > 1:
|
||||
name = '%20'.join(message.content.split()[1:])
|
||||
Handles the message and looks for the player's name.
|
||||
"""
|
||||
# Return the player's name
|
||||
name = message.content.split()[1]
|
||||
if len(message.content.split()) > 1:
|
||||
name = "%20".join(message.content.split()[1:])
|
||||
|
||||
return get_player_stats(player=name)
|
||||
return get_player_stats(player=name)
|
||||
|
||||
|
||||
def get_player_stats(player):
|
||||
"""
|
||||
get_player_stats(player)
|
||||
"""
|
||||
get_player_stats(player)
|
||||
|
||||
Makes the request to stats.quake.com and returns an embed object with a
|
||||
bunch of data about the player
|
||||
"""
|
||||
player_endpoint = "Player/Stats?name={}".format(player)
|
||||
Makes the request to stats.quake.com and returns an embed object with a
|
||||
bunch of data about the player
|
||||
"""
|
||||
player_endpoint = "Player/Stats?name={}".format(player)
|
||||
|
||||
try:
|
||||
request = requests.get("{}{}".format(base_url, player_endpoint)).json()
|
||||
return create_embed(stats=request)
|
||||
except Exception:
|
||||
return discord.Embed(
|
||||
description="404, Player not found",
|
||||
color=discord.Color.dark_red(),
|
||||
type="rich"
|
||||
)
|
||||
try:
|
||||
request = requests.get("{}{}".format(base_url, player_endpoint)).json()
|
||||
return create_embed(stats=request)
|
||||
except Exception:
|
||||
return discord.Embed(
|
||||
description="404, Player not found",
|
||||
color=discord.Color.dark_red(),
|
||||
type="rich",
|
||||
)
|
||||
|
||||
|
||||
def create_embed(stats):
|
||||
"""
|
||||
create_embed(stats)
|
||||
"""
|
||||
create_embed(stats)
|
||||
|
||||
Expects a json blob to be passed in and then builds the embed
|
||||
object
|
||||
"""
|
||||
Expects a json blob to be passed in and then builds the embed
|
||||
object
|
||||
"""
|
||||
|
||||
# Parse the json and pull out the numbers we want
|
||||
champ_name, play_time = get_favorite_champion(stats)
|
||||
fav_weapon, fav_weapon_kills = get_favorite_weapon(stats)
|
||||
kd_ratio = get_kd(stats)
|
||||
# Parse the json and pull out the numbers we want
|
||||
champ_name, play_time = get_favorite_champion(stats)
|
||||
fav_weapon, fav_weapon_kills = get_favorite_weapon(stats)
|
||||
kd_ratio = get_kd(stats)
|
||||
|
||||
embed = discord.Embed(
|
||||
description="**All Time account statistics**",
|
||||
color=discord.Color.dark_red(),
|
||||
type="rich"
|
||||
)
|
||||
embed.set_author(
|
||||
name="\nShowing stats for {}".format(stats['name']),
|
||||
icon_url="https://stats.quake.com/icons/{}.png".format(stats['playerLoadOut']['iconId'])
|
||||
)
|
||||
embed = discord.Embed(
|
||||
description="**All Time account statistics**",
|
||||
color=discord.Color.dark_red(),
|
||||
type="rich",
|
||||
)
|
||||
embed.set_author(
|
||||
name="\nShowing stats for {}".format(stats["name"]),
|
||||
icon_url="https://stats.quake.com/icons/{}.png".format(
|
||||
stats["playerLoadOut"]["iconId"]
|
||||
),
|
||||
)
|
||||
|
||||
embed.add_field(name="Current level:", value=stats['playerLevelState']['level'])
|
||||
embed.add_field(name="Total XP:", value=stats['playerLevelState']['exp'])
|
||||
embed.add_field(name="K/D:", value=kd_ratio)
|
||||
embed.add_field(name="Current level:", value=stats["playerLevelState"]["level"])
|
||||
embed.add_field(name="Total XP:", value=stats["playerLevelState"]["exp"])
|
||||
embed.add_field(name="K/D:", value=kd_ratio)
|
||||
|
||||
embed.add_field(name="\u200b", value='\u200b', inline=False)
|
||||
embed.add_field(name="\u200b", value="\u200b", inline=False)
|
||||
|
||||
embed.add_field(name="Favorite Champion:", value=champ_name)
|
||||
embed.add_field(name="Total Playtime:", value="~{} hours".format(play_time))
|
||||
embed.add_field(name="Favorite Champion:", value=champ_name)
|
||||
embed.add_field(name="Total Playtime:", value="~{} hours".format(play_time))
|
||||
|
||||
embed.add_field(name="\u200b", value='\u200b', inline=False)
|
||||
embed.add_field(name="\u200b", value="\u200b", inline=False)
|
||||
|
||||
embed.add_field(name="Favorite Weapon:", value=fav_weapon)
|
||||
embed.add_field(name="Num of kills with it:", value=fav_weapon_kills)
|
||||
embed.add_field(name="Favorite Weapon:", value=fav_weapon)
|
||||
embed.add_field(name="Num of kills with it:", value=fav_weapon_kills)
|
||||
|
||||
embed.add_field(name="\u200b", value='\u200b', inline=False)
|
||||
embed.add_field(name="\u200b", value="\u200b", inline=False)
|
||||
|
||||
# If they've played a ranked match, show the stats
|
||||
if len(stats['playerRatings']['tdm']['history']):
|
||||
match_blob = get_match_stats(stats, stats['name'])
|
||||
embed.add_field(name="Last Ranked Game:", value=match_blob)
|
||||
# If they've played a ranked match, show the stats
|
||||
if len(stats["playerRatings"]["tdm"]["history"]):
|
||||
match_blob = get_match_stats(stats, stats["name"])
|
||||
embed.add_field(name="Last Ranked Game:", value=match_blob)
|
||||
|
||||
embed.set_footer(text="Stats pulled from https://stats.quake.com", icon_url='https://stats.quake.com/icons/profile_icon_cbt_participant.png')
|
||||
embed.set_footer(
|
||||
text="Stats pulled from https://stats.quake.com",
|
||||
icon_url="https://stats.quake.com/icons/profile_icon_cbt_participant.png",
|
||||
)
|
||||
|
||||
return embed
|
||||
return embed
|
||||
|
||||
|
||||
def get_favorite_champion(blob):
|
||||
"""
|
||||
get_favorite_champion(blob)
|
||||
"""
|
||||
get_favorite_champion(blob)
|
||||
|
||||
figure out who the players favorite champion is
|
||||
"""
|
||||
play_times = {}
|
||||
all_champions = blob['playerProfileStats']['champions']
|
||||
figure out who the players favorite champion is
|
||||
"""
|
||||
play_times = {}
|
||||
all_champions = blob["playerProfileStats"]["champions"]
|
||||
|
||||
for champion in all_champions:
|
||||
for game_mode in blob['playerProfileStats']['champions'][champion]['gameModes']:
|
||||
if champion in play_times:
|
||||
play_times[champion] += blob['playerProfileStats']['champions'][champion]['gameModes'][game_mode]['timePlayed']
|
||||
play_times[champion] += blob['playerProfileStats']['champions'][champion]['gameModes'][game_mode]['rankedTimePlayed']
|
||||
else:
|
||||
play_times[champion] = blob['playerProfileStats']['champions'][champion]['gameModes'][game_mode]['timePlayed']
|
||||
play_times[champion] = blob['playerProfileStats']['champions'][champion]['gameModes'][game_mode]['rankedTimePlayed']
|
||||
for champion in all_champions:
|
||||
for game_mode in blob["playerProfileStats"]["champions"][champion]["gameModes"]:
|
||||
if champion in play_times:
|
||||
play_times[champion] += blob["playerProfileStats"]["champions"][
|
||||
champion
|
||||
]["gameModes"][game_mode]["timePlayed"]
|
||||
play_times[champion] += blob["playerProfileStats"]["champions"][
|
||||
champion
|
||||
]["gameModes"][game_mode]["rankedTimePlayed"]
|
||||
else:
|
||||
play_times[champion] = blob["playerProfileStats"]["champions"][
|
||||
champion
|
||||
]["gameModes"][game_mode]["timePlayed"]
|
||||
play_times[champion] = blob["playerProfileStats"]["champions"][
|
||||
champion
|
||||
]["gameModes"][game_mode]["rankedTimePlayed"]
|
||||
|
||||
champion_play_time = max(play_times.values()) # maximum value
|
||||
champion_name = [k for k, v in play_times.items() if v == champion_play_time][0] # getting all keys containing the `maximum`
|
||||
champion_play_time = max(play_times.values()) # maximum value
|
||||
champion_name = [k for k, v in play_times.items() if v == champion_play_time][
|
||||
0
|
||||
] # getting all keys containing the `maximum`
|
||||
|
||||
# Convert play_time from miliseconds to hours
|
||||
champion_play_time = round(float(champion_play_time)/(1000*60*60), 2)
|
||||
return(prettify(champion_name), champion_play_time)
|
||||
# Convert play_time from miliseconds to hours
|
||||
champion_play_time = round(float(champion_play_time) / (1000 * 60 * 60), 2)
|
||||
return (prettify(champion_name), champion_play_time)
|
||||
|
||||
|
||||
def get_favorite_weapon(blob):
|
||||
"""
|
||||
get_favorite_weapon(blob)
|
||||
"""
|
||||
get_favorite_weapon(blob)
|
||||
|
||||
figure out what the players favorite weapon is
|
||||
"""
|
||||
weapon_stats = {}
|
||||
all_champions = blob['playerProfileStats']['champions']
|
||||
figure out what the players favorite weapon is
|
||||
"""
|
||||
weapon_stats = {}
|
||||
all_champions = blob["playerProfileStats"]["champions"]
|
||||
|
||||
for champion in all_champions:
|
||||
for weapon in blob['playerProfileStats']['champions'][champion]['damageStatusList']:
|
||||
if weapon in weapon_stats:
|
||||
weapon_stats[weapon] += blob['playerProfileStats']['champions'][champion]['damageStatusList'][weapon]['kills']
|
||||
else:
|
||||
weapon_stats[weapon] = blob['playerProfileStats']['champions'][champion]['damageStatusList'][weapon]['kills']
|
||||
for champion in all_champions:
|
||||
for weapon in blob["playerProfileStats"]["champions"][champion][
|
||||
"damageStatusList"
|
||||
]:
|
||||
if weapon in weapon_stats:
|
||||
weapon_stats[weapon] += blob["playerProfileStats"]["champions"][
|
||||
champion
|
||||
]["damageStatusList"][weapon]["kills"]
|
||||
else:
|
||||
weapon_stats[weapon] = blob["playerProfileStats"]["champions"][
|
||||
champion
|
||||
]["damageStatusList"][weapon]["kills"]
|
||||
|
||||
total_kills = max(weapon_stats.values()) # maximum value
|
||||
weapon_name = [k for k, v in weapon_stats.items() if v == total_kills][0] # getting all keys containing the `maximum`
|
||||
total_kills = max(weapon_stats.values()) # maximum value
|
||||
weapon_name = [k for k, v in weapon_stats.items() if v == total_kills][
|
||||
0
|
||||
] # getting all keys containing the `maximum`
|
||||
|
||||
return(prettify(weapon_name), total_kills)
|
||||
return (prettify(weapon_name), total_kills)
|
||||
|
||||
|
||||
def get_kd(blob):
|
||||
"""
|
||||
get_kd(blob)
|
||||
"""
|
||||
get_kd(blob)
|
||||
|
||||
Parses json to find the player's k/d
|
||||
"""
|
||||
total_kills = 0
|
||||
total_deaths = 0
|
||||
all_champions = blob['playerProfileStats']['champions']
|
||||
Parses json to find the player's k/d
|
||||
"""
|
||||
total_kills = 0
|
||||
total_deaths = 0
|
||||
all_champions = blob["playerProfileStats"]["champions"]
|
||||
|
||||
for champion in all_champions:
|
||||
for game_mode in blob['playerProfileStats']['champions'][champion]['gameModes']:
|
||||
total_kills += blob['playerProfileStats']['champions'][champion]['gameModes'][game_mode]['kills']
|
||||
total_deaths += blob['playerProfileStats']['champions'][champion]['gameModes'][game_mode]['deaths']
|
||||
for champion in all_champions:
|
||||
for game_mode in blob["playerProfileStats"]["champions"][champion]["gameModes"]:
|
||||
total_kills += blob["playerProfileStats"]["champions"][champion][
|
||||
"gameModes"
|
||||
][game_mode]["kills"]
|
||||
total_deaths += blob["playerProfileStats"]["champions"][champion][
|
||||
"gameModes"
|
||||
][game_mode]["deaths"]
|
||||
|
||||
return round(float(total_kills / total_deaths), 2)
|
||||
|
||||
return round(float(total_kills/total_deaths), 2)
|
||||
|
||||
|
||||
def get_match_stats(blob, target_player):
|
||||
"""
|
||||
get_match_stats(blob, target_player)
|
||||
"""
|
||||
get_match_stats(blob, target_player)
|
||||
|
||||
Takes the stats blob and a player name (so we know who's K/D we care about).
|
||||
Attempts to figure out what the ranked game type was and then pulls stats from that game
|
||||
"""
|
||||
|
||||
# Figure out which ranked gametype they last played
|
||||
game_type = 'tdm' if blob['playerRatings']['tdm']['lastUpdated'] < blob['playerRatings']['duel']['lastUpdated'] else 'duel'
|
||||
Takes the stats blob and a player name (so we know who's K/D we care about).
|
||||
Attempts to figure out what the ranked game type was and then pulls stats from that game
|
||||
"""
|
||||
|
||||
most_recent_match_id = blob['playerRatings'][game_type]['history'][0]['sessionId']
|
||||
match_endpoint = "Player/Games?id={}".format(most_recent_match_id)
|
||||
match_data = requests.get("{}{}".format(base_url, match_endpoint)).json()
|
||||
fav_weapon = match_data['battleReportPersonalStatistics'][0]['bestWeapon']
|
||||
accuracy = match_data['battleReportPersonalStatistics'][0]['bestWeaponAccuracyPercent']
|
||||
score = '-'.join(str(x) for x in match_data['teamScores'])
|
||||
# Figure out which ranked gametype they last played
|
||||
game_type = (
|
||||
"tdm"
|
||||
if blob["playerRatings"]["tdm"]["lastUpdated"]
|
||||
< blob["playerRatings"]["duel"]["lastUpdated"]
|
||||
else "duel"
|
||||
)
|
||||
|
||||
for team_mate in match_data['battleReportPersonalStatistics']:
|
||||
if team_mate['nickname'].lower() == target_player.lower():
|
||||
earnedXp = team_mate['earnedXp']
|
||||
earnedFavor = team_mate['earnedFavor']
|
||||
most_recent_match_id = blob["playerRatings"][game_type]["history"][0]["sessionId"]
|
||||
match_endpoint = "Player/Games?id={}".format(most_recent_match_id)
|
||||
match_data = requests.get("{}{}".format(base_url, match_endpoint)).json()
|
||||
fav_weapon = match_data["battleReportPersonalStatistics"][0]["bestWeapon"]
|
||||
accuracy = match_data["battleReportPersonalStatistics"][0][
|
||||
"bestWeaponAccuracyPercent"
|
||||
]
|
||||
score = "-".join(str(x) for x in match_data["teamScores"])
|
||||
|
||||
kill_death_ratio = round(float(match_data['battleReportPersonalStatistics'][0]['kills']) / match_data['battleReportPersonalStatistics'][0]['deaths'], 2)
|
||||
|
||||
return_blob = "Final score: {}\nK/D: {}\nFavorite Weapon: {} | {}% Accuracy\nXP Earned: {} | Favor Earned: {}".format(
|
||||
score,
|
||||
kill_death_ratio,
|
||||
prettify(fav_weapon),
|
||||
accuracy,
|
||||
earnedXp,
|
||||
earnedFavor,
|
||||
)
|
||||
for team_mate in match_data["battleReportPersonalStatistics"]:
|
||||
if team_mate["nickname"].lower() == target_player.lower():
|
||||
earnedXp = team_mate["earnedXp"]
|
||||
earnedFavor = team_mate["earnedFavor"]
|
||||
|
||||
return return_blob
|
||||
kill_death_ratio = round(
|
||||
float(match_data["battleReportPersonalStatistics"][0]["kills"])
|
||||
/ match_data["battleReportPersonalStatistics"][0]["deaths"],
|
||||
2,
|
||||
)
|
||||
|
||||
return_blob = "Final score: {}\nK/D: {}\nFavorite Weapon: {} | {}% Accuracy\nXP Earned: {} | Favor Earned: {}".format(
|
||||
score,
|
||||
kill_death_ratio,
|
||||
prettify(fav_weapon),
|
||||
accuracy,
|
||||
earnedXp,
|
||||
earnedFavor,
|
||||
)
|
||||
|
||||
return return_blob
|
||||
|
||||
|
||||
def prettify(name):
|
||||
"""
|
||||
prettify(name)
|
||||
"""
|
||||
prettify(name)
|
||||
|
||||
Takes in an items name and returns a cleaned up / readable version
|
||||
"""
|
||||
Takes in an items name and returns a cleaned up / readable version
|
||||
"""
|
||||
|
||||
item_map = {
|
||||
'UNKNOWN_DAMAGE_TYPE' : 'Unknown Damage Type',
|
||||
'GAUNTLET' : 'Gauntlet',
|
||||
'MACHINEGUN' : 'Machinegun',
|
||||
'MACHINEGUN_GRADE1' : 'Heavy Machinegun',
|
||||
'SHOTGUN' : 'Basic Shotgun',
|
||||
'SHOTGUN_GRADE1' : 'Super Shotgun',
|
||||
'NAILGUN' : 'Nailgun',
|
||||
'NAILGUN_GRADE1' : 'Super Nailgun',
|
||||
'ROCKET_LAUNCHER' : 'Rocket Launcher',
|
||||
'LIGHTNING_GUN' : 'Lightning Gun',
|
||||
'RAILGUN' : 'Railgun',
|
||||
'LAGBOLT' : 'TriBolt',
|
||||
'ACID_DOMAIN' : 'Environmental Acid Death',
|
||||
'DAMAGE_DOMAIN' : 'Environmental Damage Death',
|
||||
'KILL_DOMAIN' : 'Environmental Kill Death',
|
||||
'DIRE_ORB' : 'Dire Orb',
|
||||
'DIRE_ORB_EXPLOSION' : 'Dire Orb Explosion',
|
||||
'DIRE_ORB_TELEFRAG' : 'Dire Orb Telefrag',
|
||||
'UNHOLY' : 'Galena\'s Totem',
|
||||
'TELEFRAG' : 'Telefrag',
|
||||
'FALL_DAMAGE' : 'Fall Damage',
|
||||
'PLASMA_TRAIL' : 'Slash\'s Plasma Trail',
|
||||
'PLASMA_TRAIL_EXPLOSION' : 'Slash\'s Plasma Trail Explosion',
|
||||
'MINING_LASER' : 'Mining Laser',
|
||||
'ABILITY_BERSERK' : 'Doom Slayer\'s Berserk Mode',
|
||||
'SWARM_GRENADE' : 'Keel\'s Swarm Grenade',
|
||||
'SB_DASH' : 'Scalbarer\'s Rush',
|
||||
'SB_STOMP' : 'Scalbarer\'s Stomp',
|
||||
'ACID_SPIT_DIRECT' : 'Acid Spit Direct',
|
||||
'VENDETTA_TELEFRAG' : 'Vendetta Telefrag',
|
||||
'ACID_DOT' : 'Sorlag\'s Acid DOT',
|
||||
'FLAME_DOT' : 'Flame DOT',
|
||||
'FLAME' : 'Flame',
|
||||
'ACID' : 'Acid',
|
||||
'DRONE_KAMIKAZE_EXPLOSION' : 'Drone Kamikaze Explosion',
|
||||
'RECON_DRONE' : 'Recon Drone',
|
||||
'RECON_DRONE_EXPLOSION' : 'Recon Drone Explosion',
|
||||
'ANARKI': 'Anarki',
|
||||
'ATHENA': 'Athena',
|
||||
'BJ_BLAZKOWICZ': 'BJ Blazkowicz',
|
||||
'CLUTCH': 'Clutch',
|
||||
'DEATH_KNIGHT': 'Death Knight',
|
||||
'DOOM_SLAYER': 'Doom Slayer',
|
||||
'EISEN': 'Eisen',
|
||||
'GALENA': 'Galena',
|
||||
'KEEL': 'Keel',
|
||||
'NYX': 'Nyx',
|
||||
'RANGER': 'Ranger',
|
||||
'SCALEBEARER': 'Scalebearer',
|
||||
'SLASH': 'Slash',
|
||||
'SORLAG': 'Sorlag',
|
||||
'STROGG': 'Strogg',
|
||||
'VISOR': 'Visor',
|
||||
}
|
||||
item_map = {
|
||||
"UNKNOWN_DAMAGE_TYPE": "Unknown Damage Type",
|
||||
"GAUNTLET": "Gauntlet",
|
||||
"MACHINEGUN": "Machinegun",
|
||||
"MACHINEGUN_GRADE1": "Heavy Machinegun",
|
||||
"SHOTGUN": "Basic Shotgun",
|
||||
"SHOTGUN_GRADE1": "Super Shotgun",
|
||||
"NAILGUN": "Nailgun",
|
||||
"NAILGUN_GRADE1": "Super Nailgun",
|
||||
"ROCKET_LAUNCHER": "Rocket Launcher",
|
||||
"LIGHTNING_GUN": "Lightning Gun",
|
||||
"RAILGUN": "Railgun",
|
||||
"LAGBOLT": "TriBolt",
|
||||
"ACID_DOMAIN": "Environmental Acid Death",
|
||||
"DAMAGE_DOMAIN": "Environmental Damage Death",
|
||||
"KILL_DOMAIN": "Environmental Kill Death",
|
||||
"DIRE_ORB": "Dire Orb",
|
||||
"DIRE_ORB_EXPLOSION": "Dire Orb Explosion",
|
||||
"DIRE_ORB_TELEFRAG": "Dire Orb Telefrag",
|
||||
"UNHOLY": "Galena's Totem",
|
||||
"TELEFRAG": "Telefrag",
|
||||
"FALL_DAMAGE": "Fall Damage",
|
||||
"PLASMA_TRAIL": "Slash's Plasma Trail",
|
||||
"PLASMA_TRAIL_EXPLOSION": "Slash's Plasma Trail Explosion",
|
||||
"MINING_LASER": "Mining Laser",
|
||||
"ABILITY_BERSERK": "Doom Slayer's Berserk Mode",
|
||||
"SWARM_GRENADE": "Keel's Swarm Grenade",
|
||||
"SB_DASH": "Scalbarer's Rush",
|
||||
"SB_STOMP": "Scalbarer's Stomp",
|
||||
"ACID_SPIT_DIRECT": "Acid Spit Direct",
|
||||
"VENDETTA_TELEFRAG": "Vendetta Telefrag",
|
||||
"ACID_DOT": "Sorlag's Acid DOT",
|
||||
"FLAME_DOT": "Flame DOT",
|
||||
"FLAME": "Flame",
|
||||
"ACID": "Acid",
|
||||
"DRONE_KAMIKAZE_EXPLOSION": "Drone Kamikaze Explosion",
|
||||
"RECON_DRONE": "Recon Drone",
|
||||
"RECON_DRONE_EXPLOSION": "Recon Drone Explosion",
|
||||
"ANARKI": "Anarki",
|
||||
"ATHENA": "Athena",
|
||||
"BJ_BLAZKOWICZ": "BJ Blazkowicz",
|
||||
"CLUTCH": "Clutch",
|
||||
"DEATH_KNIGHT": "Death Knight",
|
||||
"DOOM_SLAYER": "Doom Slayer",
|
||||
"EISEN": "Eisen",
|
||||
"GALENA": "Galena",
|
||||
"KEEL": "Keel",
|
||||
"NYX": "Nyx",
|
||||
"RANGER": "Ranger",
|
||||
"SCALEBEARER": "Scalebearer",
|
||||
"SLASH": "Slash",
|
||||
"SORLAG": "Sorlag",
|
||||
"STROGG": "Strogg",
|
||||
"VISOR": "Visor",
|
||||
}
|
||||
|
||||
return item_map[name]
|
||||
return item_map[name]
|
||||
|
@ -3,6 +3,7 @@ import wolframalpha
|
||||
|
||||
import help_methods
|
||||
|
||||
|
||||
def answer_question(message):
|
||||
"""
|
||||
answer_question(question)
|
||||
@ -12,8 +13,8 @@ def answer_question(message):
|
||||
"""
|
||||
|
||||
if len(message.split()) > 1:
|
||||
client = wolframalpha.Client('2LU2Y7-YJQTA7TL8E')
|
||||
question = ' '.join(message.split()[1:])
|
||||
client = wolframalpha.Client("2LU2Y7-YJQTA7TL8E")
|
||||
question = " ".join(message.split()[1:])
|
||||
try:
|
||||
res = client.query(question)
|
||||
return next(res.results).text
|
||||
@ -21,6 +22,6 @@ def answer_question(message):
|
||||
try:
|
||||
return wikipedia.summary(question, sentences=5)
|
||||
except Exception:
|
||||
return "Sorry, I\'m unable to answer that"
|
||||
return "Sorry, I'm unable to answer that"
|
||||
|
||||
return help_methods.get_help_message('message')
|
||||
return help_methods.get_help_message("message")
|
||||
|
@ -5,37 +5,42 @@ import threading
|
||||
|
||||
results = {}
|
||||
|
||||
def get_river_stats(river_id):
|
||||
url = requests.get("https://waterdata.usgs.gov/usa/nwis/uv?" + river_id)
|
||||
|
||||
soup = BeautifulSoup(url.content, "lxml")
|
||||
river_name = ' '.join(soup.find('h2').text.split()[2:])
|
||||
table = soup.find('table', border=1, align='left')
|
||||
title = table.find('caption').text.strip().split('--')[0].strip()
|
||||
|
||||
for rows in table.findAll('tr'):
|
||||
flow_value = rows.findAll('td',{'class': 'highlight2'})
|
||||
results[river_name] = flow_value[0].text
|
||||
def get_river_stats(river_id):
|
||||
url = requests.get("https://waterdata.usgs.gov/usa/nwis/uv?" + river_id)
|
||||
|
||||
soup = BeautifulSoup(url.content, "lxml")
|
||||
river_name = " ".join(soup.find("h2").text.split()[2:])
|
||||
table = soup.find("table", border=1, align="left")
|
||||
title = table.find("caption").text.strip().split("--")[0].strip()
|
||||
|
||||
for rows in table.findAll("tr"):
|
||||
flow_value = rows.findAll("td", {"class": "highlight2"})
|
||||
results[river_name] = flow_value[0].text
|
||||
|
||||
|
||||
def get_stats():
|
||||
river_ids = [
|
||||
'06752260',
|
||||
'07091200',
|
||||
'06719505',
|
||||
]
|
||||
threads = []
|
||||
for river in river_ids:
|
||||
t = threading.Thread(target=get_river_stats, args=(river,))
|
||||
threads.append(t)
|
||||
t.start()
|
||||
river_ids = [
|
||||
"06752260",
|
||||
"07091200",
|
||||
"06719505",
|
||||
]
|
||||
threads = []
|
||||
for river in river_ids:
|
||||
t = threading.Thread(target=get_river_stats, args=(river,))
|
||||
threads.append(t)
|
||||
t.start()
|
||||
|
||||
for x in threads:
|
||||
x.join()
|
||||
|
||||
final_string = ''
|
||||
embed = discord.Embed(description=":man_rowing_boat: Flows :man_rowing_boat:", color=0x428bca, type="rich")
|
||||
embed.set_author(name="River stats")
|
||||
for key, value in results.items():
|
||||
embed.add_field(name=key, value=value, inline=False)
|
||||
return embed
|
||||
for x in threads:
|
||||
x.join()
|
||||
|
||||
final_string = ""
|
||||
embed = discord.Embed(
|
||||
description=":man_rowing_boat: Flows :man_rowing_boat:",
|
||||
color=0x428BCA,
|
||||
type="rich",
|
||||
)
|
||||
embed.set_author(name="River stats")
|
||||
for key, value in results.items():
|
||||
embed.add_field(name=key, value=value, inline=False)
|
||||
return embed
|
||||
|
@ -5,6 +5,7 @@ This module's purpose is to handle permissions for interacting with the bot.
|
||||
The end goal is to be able to lock certain actions down to certain roles
|
||||
"""
|
||||
|
||||
|
||||
def check_permissions(user, roles_to_check):
|
||||
"""
|
||||
check_permissions(user)
|
||||
@ -26,7 +27,7 @@ def is_admin(user):
|
||||
|
||||
Returns true if the user contains the ADMIN role
|
||||
"""
|
||||
return check_permissions(user, ['ADMIN'])
|
||||
return check_permissions(user, ["ADMIN"])
|
||||
|
||||
|
||||
def is_mod(user):
|
||||
@ -35,7 +36,7 @@ def is_mod(user):
|
||||
|
||||
Returns true if the user contains the Moderator role
|
||||
"""
|
||||
return check_permissions(user, ['Moderator'])
|
||||
return check_permissions(user, ["Moderator"])
|
||||
|
||||
|
||||
def docker_permissions(user):
|
||||
|
@ -3,15 +3,16 @@ import requests
|
||||
import core_utils
|
||||
import get_from_reddit
|
||||
|
||||
|
||||
def change_bots_avatar():
|
||||
image = None
|
||||
while not image:
|
||||
image = get_from_reddit.get_image(boards='smuganimegirls')
|
||||
extension = image.split('.')[-1]
|
||||
image = get_from_reddit.get_image(boards="smuganimegirls")
|
||||
extension = image.split(".")[-1]
|
||||
local_smug = "/tmp/smug.{}".format(extension)
|
||||
|
||||
if extension.lower() in ['png', 'jpg']:
|
||||
if extension.lower() in ["png", "jpg"]:
|
||||
# save an image locally
|
||||
return open(core_utils.download_image(image, local_smug), 'rb').read()
|
||||
return open(core_utils.download_image(image, local_smug), "rb").read()
|
||||
else:
|
||||
image = None
|
||||
|
89
app/stock.py
89
app/stock.py
@ -2,48 +2,87 @@ import discord
|
||||
import os
|
||||
import requests
|
||||
|
||||
|
||||
def parse_message(msg):
|
||||
if len(msg.split()) > 1:
|
||||
try:
|
||||
res = ''
|
||||
res = ""
|
||||
for s in msg.split()[1:]:
|
||||
res = get_stock(s)
|
||||
except:
|
||||
res = '```Please input valid shares: !stock [share_name]```'
|
||||
res = "```Please input valid shares: !stock [share_name]```"
|
||||
return res
|
||||
return '```Please input at least one valid share: !stock [share_name]```'
|
||||
return "```Please input at least one valid share: !stock [share_name]```"
|
||||
|
||||
|
||||
def get_stock(share_name):
|
||||
share_name = share_name.upper()
|
||||
# Fake headers to make yahoo happy
|
||||
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'}
|
||||
request_string = "https://query1.finance.yahoo.com/v7/finance/quote?lang=en-US®ion=US&corsDomain=finance.yahoo.com&symbols=%s" % share_name
|
||||
request = requests.get(request_string, headers=headers).json()['quoteResponse']['result'][0]
|
||||
headers = {
|
||||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36"
|
||||
}
|
||||
request_string = (
|
||||
"https://query1.finance.yahoo.com/v7/finance/quote?lang=en-US®ion=US&corsDomain=finance.yahoo.com&symbols=%s"
|
||||
% share_name
|
||||
)
|
||||
request = requests.get(request_string, headers=headers).json()["quoteResponse"][
|
||||
"result"
|
||||
][0]
|
||||
|
||||
change_symbol = '+'
|
||||
change_symbol = "+"
|
||||
embed_color = 2067276
|
||||
meme_url = 'https://i.ytimg.com/vi/if-2M3K1tqk/hqdefault.jpg'
|
||||
meme_url = "https://i.ytimg.com/vi/if-2M3K1tqk/hqdefault.jpg"
|
||||
# If stock price has gone down since open, use red and a sad stonk meme
|
||||
if float(request['bid']) < float(request['regularMarketOpen']):
|
||||
change_symbol = '-'
|
||||
if float(request["bid"]) < float(request["regularMarketOpen"]):
|
||||
change_symbol = "-"
|
||||
embed_color = 15158332
|
||||
meme_url = 'https://i.ytimg.com/vi/E_XlA_IEzwM/hqdefault.jpg'
|
||||
meme_url = "https://i.ytimg.com/vi/E_XlA_IEzwM/hqdefault.jpg"
|
||||
|
||||
embed = discord.Embed(description='-------', color=embed_color, type="rich")
|
||||
embed = discord.Embed(description="-------", color=embed_color, type="rich")
|
||||
embed.set_thumbnail(url=meme_url)
|
||||
embed.set_author(name=request['longName'])
|
||||
embed.add_field(name='Current Price', value="$%s" % request['bid'], inline=False)
|
||||
embed.add_field(name='Previous Close', value="$%s" % request['regularMarketPreviousClose'], inline=False)
|
||||
embed.add_field(name='Opening price', value="$%s" % request['regularMarketOpen'], inline=False)
|
||||
embed.add_field(name='Change', value="$%s" % request['regularMarketChange'], inline=False)
|
||||
embed.add_field(name='Change percent', value="%s%%" % request['regularMarketChangePercent'], inline=False)
|
||||
embed.add_field(name='Day Low', value="$%s" % request['regularMarketDayLow'], inline=False)
|
||||
embed.add_field(name='Day High', value="$%s" % request['regularMarketDayHigh'], inline=False)
|
||||
embed.add_field(name='Day\'s Range', value=request['regularMarketDayRange'], inline=False)
|
||||
embed.add_field(name='Market Cap', value="{:,}".format(request['marketCap']), inline=False)
|
||||
embed.add_field(name='Shares Outstanding', value="{:,}".format(request['sharesOutstanding']), inline=False)
|
||||
embed.add_field(name='Link to stock price', value="https://finance.yahoo.com/quote/%s" % share_name, inline=False)
|
||||
embed.set_footer(text="Pulled from https://finance.yahoo.com\nRemember, stocks can go up 100000%, but they can only go down 100%", icon_url='https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/120/emojidex/112/chart-with-downwards-trend_1f4c9.png')
|
||||
embed.set_author(name=request["longName"])
|
||||
embed.add_field(name="Current Price", value="$%s" % request["bid"], inline=False)
|
||||
embed.add_field(
|
||||
name="Previous Close",
|
||||
value="$%s" % request["regularMarketPreviousClose"],
|
||||
inline=False,
|
||||
)
|
||||
embed.add_field(
|
||||
name="Opening price", value="$%s" % request["regularMarketOpen"], inline=False
|
||||
)
|
||||
embed.add_field(
|
||||
name="Change", value="$%s" % request["regularMarketChange"], inline=False
|
||||
)
|
||||
embed.add_field(
|
||||
name="Change percent",
|
||||
value="%s%%" % request["regularMarketChangePercent"],
|
||||
inline=False,
|
||||
)
|
||||
embed.add_field(
|
||||
name="Day Low", value="$%s" % request["regularMarketDayLow"], inline=False
|
||||
)
|
||||
embed.add_field(
|
||||
name="Day High", value="$%s" % request["regularMarketDayHigh"], inline=False
|
||||
)
|
||||
embed.add_field(
|
||||
name="Day's Range", value=request["regularMarketDayRange"], inline=False
|
||||
)
|
||||
embed.add_field(
|
||||
name="Market Cap", value="{:,}".format(request["marketCap"]), inline=False
|
||||
)
|
||||
embed.add_field(
|
||||
name="Shares Outstanding",
|
||||
value="{:,}".format(request["sharesOutstanding"]),
|
||||
inline=False,
|
||||
)
|
||||
embed.add_field(
|
||||
name="Link to stock price",
|
||||
value="https://finance.yahoo.com/quote/%s" % share_name,
|
||||
inline=False,
|
||||
)
|
||||
embed.set_footer(
|
||||
text="Pulled from https://finance.yahoo.com\nRemember, stocks can go up 100000%, but they can only go down 100%",
|
||||
icon_url="https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/120/emojidex/112/chart-with-downwards-trend_1f4c9.png",
|
||||
)
|
||||
|
||||
return embed
|
||||
|
120
app/trackdays.py
120
app/trackdays.py
@ -3,68 +3,76 @@ import json
|
||||
import requests
|
||||
import xmltodict
|
||||
|
||||
|
||||
def get_msreg():
|
||||
base_url = 'https://api.motorsportreg.com/rest/calendars/organization'
|
||||
orgs = {
|
||||
'speeddistrict': '2E22740B-E8C9-9FB9-21406A496429A28B',
|
||||
'ongrid' : '06277C99-00C9-23EB-FD08FE5275BCC0C5',
|
||||
'speedsf' : '072A885E-AD68-6F64-E88C19E4D0D21DFB',
|
||||
'turn8' : 'F3469266-BEFF-E329-4FD6C4B189ACE2A8',
|
||||
'speedventures': 'DF7453ED-BF33-DC17-2C9BFD84C1F05E86',
|
||||
'nextlevel' : 'CC23AEA4-AAB1-D087-4A10818D229DAFD2',
|
||||
# 'corsaclub' : 'CE6E69CF-BAEC-DBB6-303EE7D3EC69B8A3',
|
||||
}
|
||||
events = {}
|
||||
for org_name, org_id in orgs.items():
|
||||
xml_blob = requests.get("%s/%s?exclude_cancelled=true&postalcode=95035&radius=500" % (base_url, org_id)).text
|
||||
json_blob = json.loads(json.dumps(xmltodict.parse(xml_blob)['response']['events']))
|
||||
base_url = "https://api.motorsportreg.com/rest/calendars/organization"
|
||||
orgs = {
|
||||
"speeddistrict": "2E22740B-E8C9-9FB9-21406A496429A28B",
|
||||
"ongrid": "06277C99-00C9-23EB-FD08FE5275BCC0C5",
|
||||
"speedsf": "072A885E-AD68-6F64-E88C19E4D0D21DFB",
|
||||
"turn8": "F3469266-BEFF-E329-4FD6C4B189ACE2A8",
|
||||
"speedventures": "DF7453ED-BF33-DC17-2C9BFD84C1F05E86",
|
||||
"nextlevel": "CC23AEA4-AAB1-D087-4A10818D229DAFD2",
|
||||
"corsaclub": "CE6E69CF-BAEC-DBB6-303EE7D3EC69B8A3",
|
||||
}
|
||||
events = {}
|
||||
for org_name, org_id in orgs.items():
|
||||
xml_blob = requests.get(
|
||||
"%s/%s?exclude_cancelled=true&postalcode=94549&radius=500"
|
||||
% (base_url, org_id)
|
||||
).text
|
||||
json_blob = json.loads(
|
||||
json.dumps(xmltodict.parse(xml_blob)["response"]["events"])
|
||||
)
|
||||
|
||||
for event in json_blob['event']:
|
||||
tracks_we_care_about = ["buttonwillow", "thunderhill"]
|
||||
try:
|
||||
if any(x in event['name'].lower() for x in tracks_we_care_about):
|
||||
event_object = {
|
||||
'event_name': event['name'],
|
||||
'event_url': event['detailuri'].split('?utm')[0],
|
||||
'event_date': event['start'],
|
||||
}
|
||||
track = event['venue']['name']
|
||||
if track not in events:
|
||||
events[track] = []
|
||||
events[track].append(event_object)
|
||||
except TypeError:
|
||||
pass
|
||||
# sort track events by date
|
||||
def date_to_datetime(input):
|
||||
return datetime.strptime(input['event_date'], '%Y-%m-%d')
|
||||
for races in events.values():
|
||||
sorted(races, key=date_to_datetime)
|
||||
for event in json_blob["event"]:
|
||||
tracks_we_care_about = ["buttonwillow", "thunderhill"]
|
||||
try:
|
||||
if any(x in event["name"].lower() for x in tracks_we_care_about):
|
||||
event_object = {
|
||||
"event_name": event["name"],
|
||||
"event_url": event["detailuri"].split("?utm")[0],
|
||||
"event_date": event["start"],
|
||||
}
|
||||
track = event["venue"]["name"]
|
||||
if track not in events:
|
||||
events[track] = []
|
||||
events[track].append(event_object)
|
||||
except TypeError:
|
||||
pass
|
||||
# sort track events by date
|
||||
def date_to_datetime(input):
|
||||
return datetime.strptime(input["event_date"], "%Y-%m-%d")
|
||||
|
||||
return events
|
||||
for races in events.values():
|
||||
sorted(races, key=date_to_datetime)
|
||||
|
||||
return events
|
||||
|
||||
|
||||
def get_corsa_club():
|
||||
base_url = 'https://corsa.club'
|
||||
events = {}
|
||||
products_blob = requests.get(base_url + '/products.json').json()['products']
|
||||
for event in products_blob:
|
||||
# Filter out hoodies and what not, only care about track days that list run-groups as the options
|
||||
if any('Intermediate' in s for s in event['options'][0]['values']):
|
||||
# pp.pprint(event)
|
||||
event_object = {
|
||||
'event_name': event['title'],
|
||||
'event_url': base_url + '/products/' + event['handle'],
|
||||
'event_date': event['title'].split()[-1],
|
||||
}
|
||||
track = ' '.join(event['title'].split()[0:-1])
|
||||
try:
|
||||
if track not in events:
|
||||
events[track] = []
|
||||
events[track].append(event_object)
|
||||
except TypeError:
|
||||
pass
|
||||
base_url = "https://corsa.club"
|
||||
events = {}
|
||||
products_blob = requests.get(base_url + "/products.json").json()["products"]
|
||||
for event in products_blob:
|
||||
# Filter out hoodies and what not, only care about track days that list run-groups as the options
|
||||
if any("Intermediate" in s for s in event["options"][0]["values"]):
|
||||
# pp.pprint(event)
|
||||
event_object = {
|
||||
"event_name": event["title"],
|
||||
"event_url": base_url + "/products/" + event["handle"],
|
||||
"event_date": event["title"].split()[-1],
|
||||
}
|
||||
track = " ".join(event["title"].split()[0:-1])
|
||||
try:
|
||||
if track not in events:
|
||||
events[track] = []
|
||||
events[track].append(event_object)
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
return events
|
||||
|
||||
return events
|
||||
|
||||
# if __name__ == '__main__':
|
||||
# get_corsa_club()
|
||||
# get_corsa_club()
|
||||
|
23
app/tts.py
23
app/tts.py
@ -1,6 +1,7 @@
|
||||
from gtts import gTTS, lang
|
||||
import tempfile
|
||||
|
||||
|
||||
def text_to_speech(input):
|
||||
"""
|
||||
text_to_speech(input)
|
||||
@ -10,27 +11,24 @@ def text_to_speech(input):
|
||||
robot
|
||||
"""
|
||||
file, file_path = tempfile.mkstemp()
|
||||
message = ' '.join(input.split()[1:])
|
||||
message = " ".join(input.split()[1:])
|
||||
|
||||
language = 'en'
|
||||
language = "en"
|
||||
# check for another language denoted at the end of the message
|
||||
if ';' in message:
|
||||
print(message.split(';'))
|
||||
language = message.split(';')[1].strip()
|
||||
message = message.split(';')[0]
|
||||
if ";" in message:
|
||||
print(message.split(";"))
|
||||
language = message.split(";")[1].strip()
|
||||
message = message.split(";")[0]
|
||||
|
||||
gTTS(
|
||||
text=message,
|
||||
lang=language,
|
||||
slow=False
|
||||
).save(file_path)
|
||||
gTTS(text=message, lang=language, slow=False).save(file_path)
|
||||
|
||||
return file_path
|
||||
|
||||
|
||||
def get_all_langs():
|
||||
"""
|
||||
get_all_langs()
|
||||
|
||||
|
||||
returns a dictionary with all supported languages
|
||||
"""
|
||||
blob = ""
|
||||
@ -38,4 +36,3 @@ def get_all_langs():
|
||||
blob += "{}: {}\n".format(key, value)
|
||||
|
||||
return "```css\n{}```".format(blob)
|
||||
|
||||
|
@ -3,6 +3,7 @@ from urllib.parse import urlparse
|
||||
import requests
|
||||
import urllib
|
||||
|
||||
|
||||
def get_wall(message):
|
||||
"""
|
||||
get_wall(message)
|
||||
@ -17,7 +18,7 @@ def get_wall(message):
|
||||
search_terms = message.split()[1:]
|
||||
|
||||
# Turn search_terms into strings separated by commas
|
||||
joined_terms = ','.join(search_terms)
|
||||
joined_terms = ",".join(search_terms)
|
||||
|
||||
# Add those comma separated strings onto the end of the URL variable
|
||||
url = unsplash_url + joined_terms
|
||||
@ -31,11 +32,12 @@ def get_wall(message):
|
||||
|
||||
response = requests.get(url).url
|
||||
|
||||
if 'photo-1446704477871-62a4972035cd' in response:
|
||||
if "photo-1446704477871-62a4972035cd" in response:
|
||||
return "Could not find an image for those tags."
|
||||
else:
|
||||
return response
|
||||
|
||||
|
||||
def fcking_homepage():
|
||||
"""
|
||||
fcking_homepage()
|
||||
@ -46,8 +48,8 @@ def fcking_homepage():
|
||||
soup = BeautifulSoup(url.content)
|
||||
|
||||
for pic in soup.find_all("p"):
|
||||
if 'SWEET-ASS PICTURE' in ''.join(pic.findAll(text=True)):
|
||||
link = pic.find_next_sibling('p')
|
||||
if "http://" or "https://" in link.get('href', ''):
|
||||
link = link.find('small').find_next('a', href=True)['href']
|
||||
return urllib.parse.unquote(link.split('=')[1].split('&')[0])
|
||||
if "SWEET-ASS PICTURE" in "".join(pic.findAll(text=True)):
|
||||
link = pic.find_next_sibling("p")
|
||||
if "http://" or "https://" in link.get("href", ""):
|
||||
link = link.find("small").find_next("a", href=True)["href"]
|
||||
return urllib.parse.unquote(link.split("=")[1].split("&")[0])
|
||||
|
@ -1,9 +1,10 @@
|
||||
import re
|
||||
from urllib import parse, request
|
||||
|
||||
def parse_message(message):
|
||||
query_string = parse.urlencode({'search_query': message.split()[1:]})
|
||||
html_content = request.urlopen('http://www.youtube.com/results?' + query_string)
|
||||
search_results = re.findall('\/watch\?v=(.{11})', html_content.read().decode())
|
||||
|
||||
return 'https://www.youtube.com/watch?v=' + search_results[0]
|
||||
def parse_message(message):
|
||||
query_string = parse.urlencode({"search_query": message.split()[1:]})
|
||||
html_content = request.urlopen("http://www.youtube.com/results?" + query_string)
|
||||
search_results = re.findall("\/watch\?v=(.{11})", html_content.read().decode())
|
||||
|
||||
return "https://www.youtube.com/watch?v=" + search_results[0]
|
||||
|
Loading…
x
Reference in New Issue
Block a user