major-domo-legacy/helpers.py
2024-12-02 16:35:32 -06:00

1161 lines
52 KiB
Python

import datetime
import math
import pygsheets
from db_calls import db_get, get_player_headshot, get_team_by_abbrev, get_team_by_owner
# from db_calls import *
import asyncio
import logging
import os
import random
import json
import discord
import requests
from discord.ext import commands
from difflib import get_close_matches
SBA_SEASON = 11
PD_SEASON = 7
SBA_COLOR = 'a6ce39'
SBA_ROSTER_KEY = '1bt7LLJe6h7axkhDVlxJ4f319l8QmFB0zQH-pjM0c8a8'
SBA_STATS_KEY = '1fnqx2uxC7DT5aTnx4EkXh83crwrL0W6eJefoC1d4KH4'
SBA_STANDINGS_KEY = '1cXZcPY08RvqV_GeLvZ7PY5-0CyM-AijpJxsaFisZjBc'
SBA_ROSTER_URL = 'https://docs.google.com/spreadsheets/d/10fKx1vQ7tEjKx0OD5tnFADdjsUeFbqxMIshz2d5i-Is/edit'
SBA_BASE_URL = 'https://sba.manticorum.com'
SBA_SEASON4_DRAFT_KEY = '1lztxahGRypykfWGKd2duDGFH0omclLqFLSt-vwqdSu8'
SBA_SEASON5_DRAFT_KEY = '1euuKeWqQEUmE9OiF9wihO5LMERWP3Zwg_KsG2w-Kx54'
SBA_SEASON6_DRAFT_KEY = '13_xWG1wQy7G4UJvohD8JIUBE-7yuWT9lVta1rkAlHQE'
SBA_SEASON7_DRAFT_KEY = '1BgySsUlQf9K21_uOjQOY7O0GrRfF6zt1BBaEFlvBokY'
SBA_SEASON8_DRAFT_KEY = '1FG4cAs8OeTdrreRqu8D-APxibjB3RiEzn34KTTBLLDk'
SBA_SEASON9_DRAFT_KEY = '1eyHqaVU9rtmhG1p0ZktOrz7FMDp3c_unCcFyMMYceLc'
SBA_STANDINGS_URL = f'{SBA_BASE_URL}/standings'
SBA_SCHEDULE_URL = f'{SBA_BASE_URL}/schedule'
SBA_IMAGE_URL = f'{SBA_BASE_URL}/images'
SBA_PLAYERS_ROLE_NAME = f'Season {SBA_SEASON} Players'
PD_PLAYERS_ROLE_NAME = f'Paper Dynasty Players'
ALL_PLAYERS = [SBA_PLAYERS_ROLE_NAME, PD_PLAYERS_ROLE_NAME]
LONG_FOOTER_TEXT = f'SBa Season {SBA_SEASON} - I hope you are having a great day unless your last name ' \
f'starts with "castag".'
LOGO = f'{SBA_BASE_URL}/sba-logo.png'
INFIELD_X_CHART = {
'si1': {
'rp': 'Runner on first: Line drive hits the runner! Runner on first is out. Batter goes to first with single '
'and all other runners hold.\nNo runner on first: batter singles, runners advance 1 base.',
'e1': 'Single and Error, batter to second, runners advance 2 bases.',
'e2': 'Single and Error, batter to third, all runners score.',
'no': 'Single, runners advance 1 base.'
},
'spd': {
'rp': 'No effect; proceed with speed check',
'e1': 'Single and Error, batter to second, runners advance 2 bases.',
'e2': 'Single and Error, batter to third, all runners score.',
'no': 'Speed check, safe range equals batter\'s running rating, SI* result if safe, gb C if out'
},
'po': {
'rp': 'The batters hits a popup. None of the fielders take charge on the play and the ball drops in the '
'infield for a single! All runners advance 1 base.',
'e1': 'The catcher drops a popup for an error. All runners advance 1 base.',
'e2': 'The catcher grabs a squib in front of the plate and throws it into right field. The batter goes to '
'second and all runners score.',
'no': 'The batter pops out to the catcher.'
},
'wp': {
'rp': 'Automatic wild pitch. Catcher has trouble finding it and all base runners advance 2 bases.',
'no': 'Automatic wild pitch, all runners advance 1 base and batter rolls AB again.'
},
'x': {
'rp': 'Runner(s) on base: pitcher trips during his delivery and the ball sails for automatic wild pitch, '
'runners advance 1 base and batter rolls AB again.',
'no': 'Wild pitch check (credited as a PB). If a passed ball occurs, batter rerolls AB. '
'If no passed ball occurs, the batter fouls out to the catcher.'
},
'fo': {
'rp': 'Batter swings and misses, but is awarded first base on a catcher interference call! Baserunners advance '
'only if forced.',
'e1': 'The catcher drops a foul popup for an error. Batter rolls AB again.',
'e2': 'The catcher drops a foul popup for an error. Batter rolls AB again.',
'no': 'Runner(s) on base: make a passed ball check. If no passed ball, batter pops out to the catcher. If a '
'passed ball occurs, batter roll his AB again.\nNo runners: batter pops out to the catcher'
},
'g1': {
'rp': 'Runner on first: runner on first breaks up the double play, but umpires call runner interference and '
'the batter is out on GIDP.\nNo runners: Batter grounds out.',
'e1': 'Error, batter to first, runners advance 1 base.',
'e2': 'Error, batter to second, runners advance 2 bases.',
'no': 'Consult Groundball Chart: `!gbA`'
},
'g2': {
'rp': 'Batter lines the ball off the pitcher to the fielder who makes the play to first for the out! Runners '
'advance only if forced.',
'e1': 'Error, batter to first, runners advance 1 base.',
'e2': 'Error, batter to second, runners advance 2 bases.',
'no': 'Consult Groundball Chart: `!gbB`'
},
'g3': {
'rp': 'Batter lines the ball off the mound and deflects to the fielder who makes the play to first for the '
'out! Runners advance 1 base.',
'e1': 'Error, batter to first, runners advance 1 base.',
'e2': 'Error, batter to second, runners advance 2 bases.',
'no': 'Consult Groundball Chart: `!gbC`'
},
}
OUTFIELD_X_CHART = {
'si2': {
'rp': 'Batter singles, baserunners advance 2 bases. As the batter rounds first, the fielder throws behind him '
'and catches him off the bag for an out!',
'e1': 'Single and error, batter to second, runners advance 2 bases.',
'e2': 'Single and error, batter to third, all runners score.',
'e3': 'Single and error, batter to third, all runners score',
'no': 'Single, all runners advance 2 bases.'
},
'do2': {
'rp': 'Batter doubles, runners advance 2 bases. The outfielder throws the ball to the shortstop who executes a '
'hidden ball trick! Runner on second is called out!',
'e1': 'Double and error, batter to third, all runners score.',
'e2': 'Double and error, batter to third, and all runners score.',
'e3': 'Double and error, batter and all runners score. Little league home run!',
'no': 'Double, all runners advance 2 bases.'
},
'do3': {
'rp': 'Runner(s) on base: batter doubles and runners advance three bases as the outfielders collide!\n'
'No runners: Batter doubles, but the play is appealed. The umps rule the batter missed first base so is '
'out on the appeal!',
'e1': 'Double and error, batter to third, all runners score.',
'e2': 'Double and error, batter and all runners score. Little league home run!',
'e3': 'Double and error, batter and all runners score. Little league home run!',
'no': 'Double, all runners score.'
},
'tr3': {
'rp': 'Batter hits a ball into the gap and the outfielders collide trying to make the play! The ball rolls to '
'the wall and the batter trots home with an inside-the-park home run!',
'e1': 'Triple and error, batter and all runners score. Little league home run!',
'e2': 'Triple and error, batter and all runners score. Little league home run!',
'e3': 'Triple and error, batter and all runners score. Little league home run!',
'no': 'Triple, all runners score.'
},
'f1': {
'rp': 'The outfielder races back and makes a diving catch and collides with the wall! In the time he takes to '
'recuperate, all baserunners tag-up and advance 2 bases.',
'e1': '1 base error, runners advance 1 base.',
'e2': '2 base error, runners advance 2 bases.',
'e3': '3 base error, batter to third, all runners score.',
'no': 'Flyball A'
},
'f2': {
'rp': 'The outfielder catches the flyball for an out. If there is a runner on third, he tags-up and scores. '
'The play is appealed and the umps rule that the runner left early and is out on the appeal!',
'e1': '1 base error, runners advance 1 base.',
'e2': '2 base error, runners advance 2 bases.',
'e3': '3 base error, batter to third, all runners score.',
'no': 'Flyball B'
},
'f3': {
'rp': 'The outfielder makes a running catch in the gap! The lead runner lost track of the ball and was '
'advancing - he cannot return in time and is doubled off by the outfielder.',
'e1': '1 base error, runners advance 1 base.',
'e2': '2 base error, runners advance 2 bases.',
'e3': '3 base error, batter to third, all runners score.',
'no': 'Flyball C'
}
}
class Question:
def __init__(self, bot, channel, prompt, qtype, timeout, embed=None):
"""
Version 0.4
:param bot, discord bot object
:param channel, discord Channel object
:param prompt, string, prompt message to post
:param qtype, string, 'yesno', 'int', 'float', 'text', or 'url'
:param timeout, float, time to wait for a response
"""
if not prompt and not embed:
raise TypeError('prompt and embed may not both be None')
self.bot = bot
self.channel = channel
self.prompt = prompt
self.qtype = qtype
self.timeout = timeout
self.embed = embed
async def ask(self, responders: list):
"""
Params: responder, list of discord User objects
Returns: True/False if confirm question; full response otherwise
"""
yes = [
'yes', 'y', 'ye', 'yee', 'yerp', 'yep', 'yeet', 'yip', 'yup', 'yarp', 'si', 'fine', 'sure', 'k', 'ok',
'okay'
]
no = ['no', 'n', 'nope', 'nah', 'nyet', 'nein']
if type(responders) is not list:
raise TypeError('Responders must be a list of Members')
def yesno(mes):
return mes.channel == self.channel and mes.author in responders and mes.content.lower() in yes + no
def text(mes):
return mes.channel == self.channel and mes.author in responders
await self.channel.send(content=self.prompt, embed=self.embed)
try:
resp = await self.bot.wait_for(
'message',
timeout=self.timeout,
check=yesno if self.qtype == 'yesno' else text
)
except asyncio.TimeoutError:
return None
except Exception as e:
await self.channel.send(f'Yuck, do you know what this means?\n\n{e}')
return None
if self.qtype == 'yesno':
if resp.content.lower() in yes:
return True
else:
return False
elif self.qtype == 'int':
return int(resp.content)
elif self.qtype == 'float':
return float(resp.content)
elif self.qtype == 'url':
if resp.content[:7] == 'http://' or resp.content[:8] == 'https://':
return resp.content
else:
return False
else:
return resp.content
# Define a simple View that gives us a confirmation menu
class Confirm(discord.ui.View):
def __init__(self, responders: list, timeout: float = 300.0):
super().__init__(timeout=timeout)
if not isinstance(responders, list):
raise TypeError('responders must be a list')
self.value = None
self.responders = responders
# When the confirm button is pressed, set the inner value to `True` and
# stop the View from listening to more input.
# We also send the user an ephemeral message that we're confirming their choice.
@discord.ui.button(label='Confirm', style=discord.ButtonStyle.green)
async def confirm(self, interaction: discord.Interaction, button: discord.ui.Button):
if interaction.user not in self.responders:
return
# await interaction.response.send_message('Confirmed', ephemeral=True)
self.value = True
self.clear_items()
self.stop()
# This one is similar to the confirmation button except sets the inner value to `False`
@discord.ui.button(label='Cancel', style=discord.ButtonStyle.grey)
async def cancel(self, interaction: discord.Interaction, button: discord.ui.Button):
if interaction.user not in self.responders:
return
# await interaction.response.send_message('Cancelled', ephemeral=True)
self.value = False
self.clear_items()
self.stop()
class ButtonOptions(discord.ui.View):
def __init__(self, responders: list, timeout: float = 300.0, labels=None):
super().__init__(timeout=timeout)
if not isinstance(responders, list):
raise TypeError('responders must be a list')
self.value = None
self.responders = responders
self.options = labels
for count, x in enumerate(labels):
if count == 0:
self.option1.label = x
if x is None or x.lower() == 'na' or x == 'N/A':
self.remove_item(self.option1)
if count == 1:
self.option2.label = x
if x is None or x.lower() == 'na' or x == 'N/A':
self.remove_item(self.option2)
if count == 2:
self.option3.label = x
if x is None or x.lower() == 'na' or x == 'N/A':
self.remove_item(self.option3)
if count == 3:
self.option4.label = x
if x is None or x.lower() == 'na' or x == 'N/A':
self.remove_item(self.option4)
if count == 4:
self.option5.label = x
if x is None or x.lower() == 'na' or x == 'N/A':
self.remove_item(self.option5)
@discord.ui.button(label='Option 1', style=discord.ButtonStyle.primary)
async def option1(self, interaction: discord.Interaction, button: discord.ui.Button):
if interaction.user not in self.responders:
return
self.value = self.options[0]
self.clear_items()
self.stop()
@discord.ui.button(label='Option 2', style=discord.ButtonStyle.primary)
async def option2(self, interaction: discord.Interaction, button: discord.ui.Button):
if interaction.user not in self.responders:
return
self.value = self.options[1]
self.clear_items()
self.stop()
@discord.ui.button(label='Option 3', style=discord.ButtonStyle.primary)
async def option3(self, interaction: discord.Interaction, button: discord.ui.Button):
if interaction.user not in self.responders:
return
self.value = self.options[2]
self.clear_items()
self.stop()
@discord.ui.button(label='Option 4', style=discord.ButtonStyle.primary)
async def option4(self, interaction: discord.Interaction, button: discord.ui.Button):
if interaction.user not in self.responders:
return
self.value = self.options[3]
self.clear_items()
self.stop()
@discord.ui.button(label='Option 5', style=discord.ButtonStyle.primary)
async def option5(self, interaction: discord.Interaction, button: discord.ui.Button):
if interaction.user not in self.responders:
return
self.value = self.options[4]
self.clear_items()
self.stop()
class Pagination(discord.ui.View):
def __init__(self, responders: list, timeout: float = 300.0):
super().__init__(timeout=timeout)
if not isinstance(responders, list):
raise TypeError('responders must be a list')
self.value = None
self.responders = responders
@discord.ui.button(label='⏮️', style=discord.ButtonStyle.blurple)
async def left_button(self, interaction: discord.Interaction, button: discord.ui.Button):
if interaction.user not in self.responders:
logging.info(f'{interaction.user} is not in {self.responders}')
return
self.value = 'left'
await interaction.response.defer()
self.stop()
@discord.ui.button(label='❌️', style=discord.ButtonStyle.secondary)
async def cancel_button(self, interaction: discord.Interaction, button: discord.ui.Button):
if interaction.user not in self.responders:
logging.info(f'{interaction.user} is not in {self.responders}')
return
self.value = 'cancel'
await interaction.response.defer()
self.stop()
@discord.ui.button(label='⏭️', style=discord.ButtonStyle.blurple)
async def right_button(self, interaction: discord.Interaction, button: discord.ui.Button):
if interaction.user not in self.responders:
logging.info(f'{interaction.user} is not in {self.responders}')
return
self.value = 'right'
await interaction.response.defer()
self.stop()
def get_xchart_data(code: str):
result = ''
if code in INFIELD_X_CHART.keys():
for key in INFIELD_X_CHART[code]:
result += f'**{key.upper()}**:\n{INFIELD_X_CHART[code][key]}\n\n'
return result
elif code in OUTFIELD_X_CHART.keys():
for key in OUTFIELD_X_CHART[code]:
result += f'**{key.upper()}**:\n{OUTFIELD_X_CHART[code][key]}\n\n'
return result
return None
def get_groundball_embeds(this_command):
url_base = 'https://sombaseball.ddns.net/static/images/season04/ground-ball-chart'
if this_command in ['g1', 'g2', 'g3']:
embed = discord.Embed(title=f'Groundball {this_command.upper()} Chart')
embed.set_image(url=f'{url_base}-{this_command}.png')
return [embed]
else:
embed1 = discord.Embed(title='Groundball Chart 1/2')
embed1.set_image(url=f'{url_base}01.png')
embed2 = discord.Embed(title='Groundball Chart 2/2')
embed2.set_image(url=f'{url_base}02.png')
return [embed1, embed2]
def old_rand_conf_gif():
conf_gifs = [
'https://tenor.com/view/boom-annakendrick-pitchperfect-pitchperfect2-micdrop-gif-5143507',
'https://tenor.com/view/boom-annakendrick-pitchperfect-pitchperfect2-micdrop-gif-5143507',
'https://tenor.com/view/boom-annakendrick-pitchperfect-pitchperfect2-micdrop-gif-5143507',
'https://tenor.com/view/explosion-boom-iron-man-gif-14282225',
'https://tenor.com/view/betty-white-dab-consider-it-done-gif-11972415',
'https://tenor.com/view/done-and-done-spongebob-finished-just-did-it-gif-10843280',
'https://tenor.com/view/thumbs-up-okay-ok-well-done-gif-13840394',
'https://tenor.com/view/tinkerbell-peter-pan-all-done-gif-15003723',
'https://tenor.com/view/done-and-done-ron-swanson-gotchu-gif-10843254',
'https://tenor.com/view/sponge-bob-thumbs-up-ok-smile-gif-12038157',
'https://tenor.com/view/thumbs-up-cool-okay-bye-gif-8633196',
'https://media.giphy.com/media/zCME2Cd20Czvy/giphy.gif',
'https://media.giphy.com/media/xT0xeJpckCr0qGAFna/giphy.gif',
'https://media0.giphy.com/media/l0MYw3oeYCUJhj5FC/200.gif',
'https://media2.giphy.com/media/52FcaTVc9Y1rk7q1NQ/200.gif',
'https://i0.wp.com/media1.giphy.com/media/iwvuPyfi7z14I/giphy.gif',
'https://media1.tenor.com/images/859a2d3b201fbacec13904242976b9e0/tenor.gif',
'https://media.giphy.com/media/3o6ZsZbUukGiYMf2a4/giphy.gif',
'https://media.giphy.com/media/l0Iyl55kTeh71nTXy/giphy.gif',
'https://media.giphy.com/media/3o7qDEq2bMbcbPRQ2c/giphy.gif',
'https://media.giphy.com/media/3orieTbyzN9QNCDANa/giphy.gif',
'https://media.giphy.com/media/l3V0JGUuz4xght7Py/giphy.gif',
'https://media.giphy.com/media/o1H5mqZKB0RCE/giphy.gif',
'https://media.giphy.com/media/Rhf0uSWt1P2TFqVMZK/giphy.gif',
'https://media.giphy.com/media/UIMAFTRUcf6V71BGsd/giphy.gif',
'https://media.giphy.com/media/xUOwFYnEb6rv4Oxx6M/giphy.gif',
'https://media.giphy.com/media/6bdiLSKOwgR6ekaTSS/giphy.gif',
'https://tenor.com/bc1OJ.gif',
'https://tenor.com/1EmF.gif',
'https://tenor.com/ZYCh.gif',
'https://tenor.com/patd.gif',
'https://tenor.com/u6mU.gif',
'https://tenor.com/x2sa.gif',
'https://tenor.com/bAVeS.gif',
'https://tenor.com/bxOcj.gif',
'https://tenor.com/ETJ7.gif',
'https://tenor.com/bpH3g.gif',
'https://tenor.com/biF9q.gif',
'https://tenor.com/OySS.gif',
'https://tenor.com/bvVFv.gif',
'https://tenor.com/bFeqA.gif'
]
return conf_gifs[random.randint(0, len(conf_gifs) - 1)]
def random_conf_gif():
req_url = 'https://api.giphy.com/v1/gifs/translate?s=all done&api_key=H86xibttEuUcslgmMM6uu74IgLEZ7UOD'
resp = requests.get(req_url, timeout=3)
if resp.status_code == 200:
data = resp.json()
if 'trump' in data['data']['title']:
return old_rand_conf_gif()
else:
return data['data']['url']
else:
logging.warning(resp.text)
raise ValueError(f'DB: {resp.text}')
def random_salute_gif():
salute_gifs = [
'https://media.giphy.com/media/fSAyceY3BCgtiQGnJs/giphy.gif',
'https://media.giphy.com/media/bsWDUSFUmJCOk/giphy.gif',
'https://media.giphy.com/media/hStvd5LiWCFzYNyxR4/giphy.gif',
'https://media.giphy.com/media/RhSR5xXDsXJ7jbnrRW/giphy.gif',
'https://media.giphy.com/media/lNQvrlPdbmZUU2wlh9/giphy.gif',
'https://gfycat.com/skeletaldependableandeancat',
'https://i.gifer.com/5EJk.gif',
'https://tenor.com/baJUV.gif',
'https://tenor.com/bdnQH.gif',
'https://tenor.com/bikQU.gif',
'https://i.pinimg.com/originals/04/36/bf/0436bfc9861b4b57ffffda82d3adad6e.gif',
'https://media.giphy.com/media/6RtOG4Q7v34kw/giphy.gif',
'https://keyassets-p2.timeincuk.net/wp/prod/wp-content/uploads/sites/42/2017/04/anigif_'
'enhanced-946-1433453114-7.gif',
'https://keyassets-p2.timeincuk.net/wp/prod/wp-content/uploads/sites/42/2017/04/100c5d677cc28ea3f15'
'4c70d641f655b_meme-crying-gif-crying-gif-meme_620-340.gif',
'https://media.giphy.com/media/fnKd6rCHaZoGdzLjjA/giphy.gif',
'https://media.giphy.com/media/47D5jmVc4f7ylygXYD/giphy.gif',
'https://media.giphy.com/media/I4wGMXoi2kMDe/giphy.gif',
]
return salute_gifs[random.randint(0, len(salute_gifs) - 1)]
def random_conf_word():
conf_words = [
'dope',
'cool',
'got it',
'noice',
'ok',
'lit',
]
return conf_words[random.randint(0, len(conf_words) - 1)]
def random_codename():
all_names = [
'Shong', 'DerekSux', 'JoeSux', 'CalSux', 'Friend', 'Andrea', 'Ent', 'Lindved', 'Camp', 'Idyll', 'Elaphus',
'Turki', 'Shrimp', 'Primary', 'Anglica', 'Shail', 'Blanket', 'Baffled', 'Deer', 'Thisted', 'Brisk', 'Shy',
'Table', 'Jorts', 'Renati', 'Gisky', 'Prig', 'Bathtub', 'Gallery', 'Mavas', 'Chird', 'Oxyura', 'Mydal', 'Brown',
'Vasen', 'Worthy', 'Bivver', 'Cirlus', 'Self', 'Len', 'Sharp', 'Dart', 'Crepis', 'Ferina', 'Curl', 'Lancome',
'Stuff', 'Glove', 'Consist', 'Smig', 'Egg', 'Pleat', 'Picture', 'Spin', 'Ridgty', 'Ickled', 'Abashed', 'Haul',
'Cordage', 'Chivery', 'Stointy', 'Baa', 'Here', 'Ulmi', 'Tour', 'Tribe', 'Crunch', 'Used', 'Pigface', 'Audit',
'Written', 'Once', 'Fickle', 'Drugged', 'Swarm', 'Blimber', 'Torso', 'Retusa', 'Hockey', 'Pusty', 'Sallow',
'Next', 'Mansion', 'Glass', 'Screen', 'Josiah', 'Bonkey', 'Stuff', 'Sane', 'Blooded', 'Gnat', 'Liparis',
'Ocean', 'Sway', 'Roband', 'Still', 'Ribba', 'Biryani', 'Halibut', 'Flyn', 'Until', 'Depend', 'Intel',
'Affinis', 'Chef', 'Trounce', 'Crawl', 'Grab', 'Eggs', 'Malfroy', 'Sitta', 'Cretin', 'May', 'Smithii',
'Saffron', 'Crummy', 'Powered', 'Rail', 'Trait', 'Koiled', 'Bronze', 'Quickly', 'Vikis', 'Trift', 'Jubilar',
'Deft', 'Juncus', 'Sodding', 'Distant', 'Poecile', 'Pipe', 'Sell', 'Inops', 'Peusi', 'Sparrow', 'Yams',
'Kidneys', 'Artery', 'Vuffin', 'Boink', 'Bos', 'Notable', 'Alba', 'Spurge', 'Ruby', 'Cilia', 'Pellow', 'Nox',
'Woozy', 'Semvik', 'Tyda', 'Season', 'Lychnis', 'Ibestad', 'Bagge', 'Marked', 'Browdie', 'Fisher', 'Tilly',
'Troll', 'Gypsy', 'Thisted', 'Flirt', 'Stop', 'Radiate', 'Poop', 'Plenty', 'Jeff', 'Magpie', 'Roof', 'Ent',
'Dumbo', 'Pride', 'Weights', 'Winted', 'Dolden', 'Meotica', 'Yikes', 'Teeny', 'Fizz', 'Eide', 'Foetida',
'Crash', 'Mann', 'Salong', 'Cetti', 'Balloon', 'Petite', 'Find', 'Sputter', 'Patula', 'Upstage', 'Aurora',
'Dadson', 'Drate', 'Heidal', 'Robin', 'Auditor', 'Ithil', 'Warmen', 'Pat', 'Muppet', '007', 'Advantage',
'Alert', 'Backhander', 'Badass', 'Blade', 'Blaze', 'Blockade', 'Blockbuster', 'Boxer', 'Brimstone', 'Broadway',
'Buccaneer', 'Champion', 'Cliffhanger', 'Coachman', 'Comet', 'Commander', 'Courier', 'Cowboy', 'Crawler',
'Crossroads', 'DeepSpace', 'Desperado', 'Double-Decker', 'Echelon', 'Edge', 'Encore', 'EnRoute', 'Escape',
'Eureka', 'Evangelist', 'Excursion', 'Explorer', 'Fantastic', 'Firefight', 'Foray', 'Forge', 'Freeway',
'Frontier', 'FunMachine', 'Galaxy', 'GameOver', 'Genesis', 'Hacker', 'Hawkeye', 'Haybailer', 'Haystack',
'Hexagon', 'Hitman', 'Hustler', 'Iceberg', 'Impossible', 'Impulse', 'Invader', 'Inventor', 'IronWolf',
'Jackrabbit', 'Juniper', 'Keyhole', 'Lancelot', 'Liftoff', 'MadHatter', 'Magnum', 'Majestic', 'Merlin',
'Multiplier', 'Netiquette', 'Nomad', 'Octagon', 'Offense', 'OliveBranch', 'OlympicTorch', 'Omega', 'Onyx',
'Orbit', 'OuterSpace', 'Outlaw', 'Patron', 'Patriot', 'Pegasus', 'Pentagon', 'Pilgrim', 'Pinball', 'Pinnacle',
'Pipeline', 'Pirate', 'Portal', 'Predator', 'Prism', 'RagingBull', 'Ragtime', 'Reunion', 'Ricochet',
'Roadrunner', 'Rockstar', 'RobinHood', 'Rover', 'Runabout', 'Sapphire', 'Scrappy', 'Seige', 'Shadow',
'Shakedown', 'Shockwave', 'Shooter', 'Showdown', 'SixPack', 'SlamDunk', 'Slasher', 'Sledgehammer', 'Spirit',
'Spotlight', 'Starlight', 'Steamroller', 'Stride', 'Sunrise', 'Superhuman', 'Supernova', 'SuperBowl', 'Sunset',
'Sweetheart', 'TopHand', 'Touchdown', 'Tour', 'Trailblazer', 'Transit', 'Trekker', 'Trio', 'TriplePlay',
'TripleThreat', 'Universe', 'Unstoppable', 'Utopia', 'Vicinity', 'Vector', 'Vigilance', 'Vigilante', 'Vista',
'Visage', 'Vis-à-vis', 'VIP', 'Volcano', 'Volley', 'Whizzler', 'Wingman', 'Badger', 'BlackCat', 'Bobcat',
'Caracal', 'Cheetah', 'Cougar', 'Jaguar', 'Leopard', 'Lion', 'Lynx', 'MountainLion', 'Ocelot', 'Panther',
'Puma', 'Siamese', 'Serval', 'Tiger', 'Wolverine', 'Abispa', 'Andrena', 'BlackWidow', 'Cataglyphis',
'Centipede', 'Cephalotes', 'Formica', 'Hornet', 'Jellyfish', 'Scorpion', 'Tarantula', 'Yellowjacket', 'Wasp',
'Apollo', 'Ares', 'Artemis', 'Athena', 'Hercules', 'Hermes', 'Iris', 'Medusa', 'Nemesis', 'Neptune', 'Perseus',
'Poseidon', 'Triton', 'Zeus', 'Aquarius', 'Aries', 'Cancer', 'Capricorn', 'Gemini', 'Libra', 'Leo', 'Pisces',
'Sagittarius', 'Scorpio', 'Taurus', 'Virgo', 'Andromeda', 'Aquila', 'Cassiopeia', 'Cepheus', 'Cygnus',
'Delphinus', 'Drako', 'Lyra', 'Orion', 'Perseus', 'Serpens', 'Triangulum', 'Anaconda', 'Boa', 'Cobra',
'Copperhead', 'Cottonmouth', 'Garter', 'Kingsnake', 'Mamba', 'Python', 'Rattler', 'Sidewinder', 'Taipan',
'Viper', 'Alligator', 'Barracuda', 'Crocodile', 'Gator', 'GreatWhite', 'Hammerhead', 'Jaws', 'Lionfish',
'Mako', 'Moray', 'Orca', 'Piranha', 'Shark', 'Stingray', 'Axe', 'BattleAxe', 'Bayonet', 'Blade', 'Crossbowe',
'Dagger', 'Excalibur', 'Halberd', 'Hatchet', 'Machete', 'Saber', 'Samurai', 'Scimitar', 'Scythe', 'Stiletto',
'Spear', 'Sword', 'Aurora', 'Avalanche', 'Blizzard', 'Cyclone', 'Dewdrop', 'Downpour', 'Duststorm', 'Fogbank',
'Freeze', 'Frost', 'GullyWasher', 'Gust', 'Hurricane', 'IceStorm', 'JetStream', 'Lightning', 'Mist', 'Monsoon',
'Rainbow', 'Raindrop', 'SandStorm', 'Seabreeze', 'Snowflake', 'Stratosphere', 'Storm', 'Sunrise', 'Sunset',
'Tornado', 'Thunder', 'Thunderbolt', 'Thunderstorm', 'TropicalStorm', 'Twister', 'Typhoon', 'Updraft', 'Vortex',
'Waterspout', 'Whirlwind', 'WindChill', 'Archimedes', 'Aristotle', 'Confucius', 'Copernicus', 'Curie',
'daVinci', 'Darwin', 'Descartes', 'Edison', 'Einstein', 'Epicurus', 'Freud', 'Galileo', 'Hawking',
'Machiavelli', 'Marx', 'Newton', 'Pascal', 'Pasteur', 'Plato', 'Sagan', 'Socrates', 'Tesla', 'Voltaire',
'Baccarat', 'Backgammon', 'Blackjack', 'Chess', 'Jenga', 'Jeopardy', 'Keno', 'Monopoly', 'Pictionary', 'Poker',
'Scrabble', 'TrivialPursuit', 'Twister', 'Roulette', 'Stratego', 'Yahtzee', 'Aquaman', 'Batman', 'BlackPanther',
'BlackWidow', 'CaptainAmerica', 'Catwoman', 'Daredevil', 'Dr.Strange', 'Flash', 'GreenArrow', 'GreenLantern',
'Hulk', 'IronMan', 'Phantom', 'Thor', 'SilverSurfer', 'SpiderMan', 'Supergirl', 'Superman', 'WonderWoman',
'Wolverine', 'Hypersonic', 'Lightspeed', 'Mach1,2,3,4,etc', 'Supersonic', 'WarpSpeed', 'Amiatina', 'Andalusian',
'Appaloosa', 'Clydesdale', 'Colt', 'Falabella', 'Knabstrupper', 'Lipizzan', 'Lucitano', 'Maverick', 'Mustang',
'Palomino', 'Pony', 'QuarterHorse', 'Stallion', 'Thoroughbred', 'Zebra', 'Antigua', 'Aruba', 'Azores', 'Baja',
'Bali', 'Barbados', 'Bermuda', 'BoraBora', 'Borneo', 'Capri', 'Cayman', 'Corfu', 'Cozumel', 'Curacao', 'Fiji',
'Galapagos', 'Hawaii', 'Ibiza', 'Jamaica', 'Kauai', 'Lanai', 'Majorca', 'Maldives', 'Maui', 'Mykonos',
'Nantucket', 'Oahu', 'Tahiti', 'Tortuga', 'Roatan', 'Santorini', 'Seychelles', 'St.Johns', 'St.Lucia',
'Albatross', 'BaldEagle', 'Blackhawk', 'BlueJay', 'Chukar', 'Condor', 'Crane', 'Dove', 'Eagle', 'Falcon',
'Goose(GoldenGoose)', 'Grouse', 'Hawk', 'Heron', 'Hornbill', 'Hummingbird', 'Lark', 'Mallard', 'Oriole',
'Osprey', 'Owl', 'Parrot', 'Penguin', 'Peregrine', 'Pelican', 'Pheasant', 'Quail', 'Raptor', 'Raven', 'Robin',
'Sandpiper', 'Seagull', 'Sparrow', 'Stork', 'Thunderbird', 'Toucan', 'Vulture', 'Waterfowl', 'Woodpecker',
'Wren', 'C-3PO', 'Chewbacca', 'Dagobah', 'DarthVader', 'DeathStar', 'Devaron', 'Droid', 'Endor', 'Ewok', 'Hoth',
'Jakku', 'Jedi', 'Leia', 'Lightsaber', 'Lothal', 'Naboo', 'Padawan', 'R2-D2', 'Scarif', 'Sith', 'Skywalker',
'Stormtrooper', 'Tatooine', 'Wookie', 'Yoda', 'Zanbar', 'Canoe', 'Catamaran', 'Cruiser', 'Cutter', 'Ferry',
'Galleon', 'Gondola', 'Hovercraft', 'Hydrofoil', 'Jetski', 'Kayak', 'Longboat', 'Motorboat', 'Outrigger',
'PirateShip', 'Riverboat', 'Sailboat', 'Skipjack', 'Schooner', 'Skiff', 'Sloop', 'Steamboat', 'Tanker',
'Trimaran', 'Trawler', 'Tugboat', 'U-boat', 'Yacht', 'Yawl', 'Lancer', 'Volunteer', 'Searchlight', 'Passkey',
'Deacon', 'Rawhide', 'Timberwolf', 'Eagle', 'Tumbler', 'Renegade', 'Mogul'
]
this_name = all_names[random.randint(0, len(all_names) - 1)]
return this_name
def random_no_phrase():
phrases = [
'uhh...no',
'lol no',
'nope',
'not again',
'huh uh',
'nah'
]
this_phrase = phrases[random.randint(0, len(phrases) - 1)]
return this_phrase
def random_soccer():
all_phrases = [
'Ugh, this again',
'Bro I can\'t with this',
'Fucking soccer again?',
'Gtfo with this soccer stuff',
'I\'m just gonna start deleting stuff',
'No\nNo\n\nNooooo\n\n\nFucking no more soccer\n\n\n\n\n\nNooooooooooooooooooo',
'Omg with this soccer shit again',
'Do you ever want to win an sba game again?'
]
this_phrase = all_phrases[random.randint(0, len(all_phrases) - 1)]
return this_phrase
async def get_emoji(ctx, name, return_empty=True):
try:
emoji = await commands.converter.EmojiConverter().convert(ctx, name)
except:
if return_empty:
emoji = ''
else:
return name
return emoji
async def team_emoji(ctx, team):
try:
emoji = await get_emoji(ctx, f'{team["sname"].lower().replace(" ","")}')
except:
emoji = ''
return emoji
async def fuzzy_player_search(ctx, channel, bot, name, master_list, author = None):
"""
Takes a name to search and returns the name of the best match
:param ctx: discord context
:param channel: discord channel
:param bot: discord.py bot object
:param name: string
:param master_list: list of names
:return:
"""
logging.warning(f'fuzzy player search - len(master_list): {len(master_list)}')
if name.lower() in master_list:
return name.lower()
if author is None:
author = ctx.author
great_matches = get_close_matches(name, master_list, cutoff=0.8)
if len(great_matches) == 1:
return great_matches[0]
elif len(great_matches) > 0:
matches = great_matches
else:
matches = get_close_matches(name, master_list, n=6)
if len(matches) == 1:
return matches[0]
if not matches:
raise ValueError(f'{name.title()} was not found')
embed = discord.Embed(
title="Did You Mean...",
description='Enter the number of the card you would like to see.',
color=0x7FC600
)
count = 1
for x in matches:
embed.add_field(name=f'{count}', value=x, inline=False)
count += 1
embed.set_footer(text='These are the closest matches. Spell better if they\'re not who you want.')
this_q = Question(bot, channel, None, 'int', 45, embed=embed)
resp = await this_q.ask([author])
if not resp:
return None
if resp < count:
return matches[resp - 1]
else:
raise ValueError(f'{resp} is not a valid response.')
def get_player_positions(player):
"""
:param player: Player instance
:return list: positions (ex: ['1B', '3B'] or ['SP', 'RP', 'CP'])
"""
positions = []
if player['pos_1']:
positions.append(player['pos_1'])
if player['pos_2']:
positions.append(player['pos_2'])
if player['pos_3']:
positions.append(player['pos_3'])
if player['pos_4']:
positions.append(player['pos_4'])
if player['pos_5']:
positions.append(player['pos_5'])
if player['pos_6']:
positions.append(player['pos_6'])
if player['pos_7']:
positions.append(player['pos_7'])
if player['pos_8']:
positions.append(player['pos_8'])
return positions
def get_team_embed(title, team=None, thumbnail: bool = True):
if team:
embed = discord.Embed(
title=title,
color=int(team["color"], 16) if team["color"] and int(team["color"], 16) <= 16777215
else int(SBA_COLOR, 16)
)
if thumbnail:
if 'thumbnail' in team:
embed.set_thumbnail(url=team["thumbnail"] if team["thumbnail"] else LOGO)
elif 'logo' in team:
embed.set_thumbnail(url=team["logo"] if team["logo"] else LOGO)
embed.set_footer(text=f'SBa Season {team["season"]}', icon_url=LOGO)
else:
embed = discord.Embed(
title=title,
color=int(SBA_COLOR, 16)
)
if thumbnail:
embed.set_thumbnail(url=LOGO)
embed.set_footer(text=f'SBa Season {SBA_SEASON}', icon_url=LOGO)
return embed
async def get_or_create_role(ctx, role_name, mentionable=True):
this_role = discord.utils.get(ctx.guild.roles, name=role_name)
logging.info(f'this_role: {this_role} / role_name: {role_name} (POST SEARCH)')
if not this_role:
this_role = await ctx.guild.create_role(name=role_name, mentionable=mentionable)
logging.info(f'this_role: {this_role} / role_name: {role_name} (PRE RETURN)')
return this_role
def get_role(ctx, role_name, bot=None):
role = None
if not ctx:
if bot:
guild = bot.get_guild(int(os.environ.get('GUILD_ID')))
if not guild:
logging.error('Cannot send to channel - bot not logged in')
return
role = discord.utils.get(guild.roles, name=role_name)
else:
role = discord.utils.get(ctx.guild.roles, name=role_name)
logging.info(f'this_role: {role} / role_name: {role_name} (PRE RETURN)')
if role:
return role
else:
return None
def get_team_role(ctx, team, bot=None):
return get_role(ctx, team['lname'], bot)
async def send_to_channel(bot, channel_name, content=None, embed=None):
guild = bot.get_guild(int(os.environ.get('GUILD_ID')))
if not guild:
logging.error('Cannot send to channel - bot not logged in')
return
this_channel = discord.utils.get(guild.text_channels, name=channel_name)
if not this_channel:
this_channel = discord.utils.get(guild.text_channels, id=channel_name)
if not this_channel:
raise NameError(f'**{channel_name}** channel not found')
await this_channel.send(content=content, embed=embed)
async def get_player_embed(player, current, ctx=None, season=None):
if season is None:
season = current['season']
player_name = player['name']
if player['il_return']:
if player['team']['abbrev'][-2:].lower() == 'il':
player_name = f'🏥 {player_name}'
else:
player_name = f'{await get_emoji(ctx, "WeenieHut", False)}{player_name}'
embed = get_team_embed(f'{player_name}', player["team"])
embed.set_footer(text=f'SBa Season {current["season"]}', icon_url=LOGO)
embed.add_field(name='Player ID', value=f'{player["id"]}')
embed.set_image(url=player['image'])
# embed.description = f'Player ID {player["id"]}'
if player['headshot']:
embed.set_thumbnail(url=player['headshot'])
elif player['vanity_card']:
embed.set_thumbnail(url=player['vanity_card'])
else:
player_photo = await get_player_headshot(player['name'])
if player_photo:
embed.set_thumbnail(url=player_photo)
t_query = await db_get('transactions', params=[
('season', current['season']), ('week_start', current['week']), ('week_end', current['week'] + 1),
('player_id', player['id'])
])
d_query = await db_get('draftpicks', params=[
('season', current['season']), ('player_id', player['id'])
])
positions = get_player_positions(player)
if len(positions) > 0:
embed.add_field(name=f'Position{"s" if len(positions) > 1 else ""}', value=",".join(positions))
embed.add_field(name='sWAR', value=player['wara'])
player_pages = f'[SBa]({get_player_url(player)}) / ' \
f'[BBRef]({get_player_url(player, "bbref")})'
embed.add_field(name='Player Page', value=player_pages)
# if player['last_game']:
# embed.add_field(name='Last G', value=player['last_game'])
# if player['last_game2']:
# embed.add_field(name='Last G-2', value=player['last_game2'])
if player['injury_rating'] is not None:
inj_string = f'{player["injury_rating"]}'
if player['pos_1'] in ['SP', 'RP']:
inj_code = player['injury_rating'][:1]
inj_string += f'(6-{13 - int(inj_code)})'
embed.add_field(name='Injury', value=inj_string)
if player['pitcher_injury'] is not None:
if player['pitcher_injury']:
embed.add_field(name='P Injury', value=f'{player["pitcher_injury"]} (6-{13 - player["pitcher_injury"]})')
else:
embed.add_field(name='P Injury', value=f'{player["pitcher_injury"]} (---)')
if d_query['count'] > 0:
pick = d_query['picks'][0]
num = pick["overall"] % 16
if num == 0:
num = 16
embed.add_field(name='Draft Pick', value=f'{pick["round"]}.{num} ({pick["owner"]["abbrev"]})')
else:
embed.add_field(name='Draft Pick', value=f'None')
embed.add_field(name='Current Team', value=player['team']['sname'])
if player['team']['abbrev'][-3:].lower() == 'mil':
major_team = await get_team_by_abbrev(player['team']['abbrev'][:-3], season=player['season'])
embed.add_field(name='SBa Affiliate', value=major_team['sname'])
if player['demotion_week'] is not None:
if player['demotion_week'] > current['week']:
embed.add_field(name='Dem Week', value=player["demotion_week"])
if player['il_return']:
embed.add_field(name='IL Return', value=player['il_return'])
for x in t_query['transactions']:
if x['week'] == current['week']:
embed.add_field(name='Last Week', value=f'{x["oldteam"]["sname"]}')
if x['week'] == current['week'] + 1:
embed.add_field(name='Next Week', value=f'To {x["newteam"]["sname"]}')
if player['season'] < 8:
b, p = None, None
batting_string = None
pitching_string = None
batter_priority = True
b_query = await db_get('battingstats/totals', params=[
('season', player['season']), ('player_id', player['id']), ('s_type', 'regular')])
if b_query['count'] > 0:
b = b_query['stats'][0]
if b['ab'] > 0:
singles = b['hit'] - b['hr'] - b['triple'] - b['double']
avg = b['hit'] / b['ab']
obp = (b['hit'] + b['bb'] + b['ibb'] + b['hbp']) / b['pa']
slg = ((b['hr'] * 4) + (b['triple'] * 3) + (b['double'] * 2) + singles) / b['ab']
ops = obp + slg
woba = ((b['bb'] * .69) + (b['hbp'] * .72) + (singles * .89) + (b['double'] * 1.27) +
(b['triple'] * 1.62) + (b['hr'] * 2.1)) / (b['pa'] - b['hbp'] - b['sac'])
ab = f'{b["ab"]:.0f}'
run = f'{b["run"]:.0f}'
hit = f'{b["hit"]:.0f}'
double = f'{b["double"]:.0f}'
triple = f'{b["triple"]:.0f}'
hr = f'{b["hr"]:.0f}'
rbi = f'{b["rbi"]:.0f}'
sb = f'{b["sb"]:.0f}'
cs = f'{b["cs"]:.0f}'
so = f'{b["so"]:.0f}'
batting_string = f'```\n' \
f' AVG OBP SLG OPS\n' \
f' {avg:.3f} {obp:.3f} {slg:.3f} {ops:.3f}\n``````\n' \
f' AB R H 2B 3B HR RBI SB SO\n' \
f'{ab: >3} {run: >2} {hit: ^3} {double: >2} {triple: >2} {hr: >2} {rbi: >3} ' \
f'{sb: >2} {so: ^3}\n```'
p_query = await db_get('pitchingstats/totals', params=[
('season', player['season']), ('player_id', player['id']), ('s_type', 'regular')])
if p_query['count'] > 0:
p = p_query['stats'][0]
if p['ip'] > 0:
if b is not None and p['ip'] > b['pa']:
batter_priority = False
win = f'{p["win"]:.0f}'
loss = f'{p["loss"]:.0f}'
save = f'{p["sv"]:.0f}'
era = f'{(p["erun"] * 9) / p["ip"]:.2f}'
# game = f'{p["game"]:.0f}'
# gs = f'{p["gs"]:.0f}'
ip = f'{p["ip"]:.0f}'
if p["ip"] % 1 == 0:
ip += '.0'
elif str(p["ip"] % 1)[2] == '3':
ip += '.1'
else:
ip += '.2'
so = f'{p["so"]:.0f}'
whip = f'{(p["bb"] + p["hit"]) / p["ip"]:.2f}'
pitching_string = f'```\n' \
f' W L SV ERA IP SO WHIP\n' \
f'{win: >2} {loss: >2} {save: >2} {era: >5} {ip: >5} ' \
f'{so: >3} {whip: >4}\n```'
if batting_string and batter_priority:
embed.add_field(name='Batting Stats', value=batting_string, inline=False)
if pitching_string:
embed.add_field(name='Pitching Stats', value=pitching_string, inline=False)
if batting_string and not batter_priority:
embed.add_field(name='Batting Stats', value=batting_string, inline=False)
else:
b_query = await db_get('plays/batting', params=[
('player_id', player['id']), ('min_wpa', 0), ('s_type', 'regular')
])
p_query = await db_get('plays/pitching', params=[('player_id', player['id']), ('s_type', 'regular')])
batter_priority = True
b, p, batting_string, pitching_string = None, None, None, None
if b_query['count'] > 0:
b = b_query['stats'][0]
batting_string = f'```\n' \
f' AVG OBP SLG\n' \
f' {b["avg"]:.3f} {b["obp"]:.3f} {b["slg"]:.3f}\n``````\n' \
f' OPS wOBA WPA\n' \
f' {b["ops"]:.3f} {b["woba"]:.3f} {b["wpa"]:.3f}\n``````\n' \
f' PA H RBI 2B 3B HR SB\n' \
f'{b["pa"]: >3} {b["hit"]: ^3} {b["rbi"]: ^3} {b["double"]: >2} {b["triple"]: >2} ' \
f'{b["hr"]: >2} {b["sb"]: >2}```\n'
if p_query['count'] > 0:
p = p_query['stats'][0]
if b is None or p["tbf"] > b["pa"]:
batter_priority = False
ip_whole = math.floor(p['outs'] / 3)
ip_denom = p['outs'] % 3
ips = ip_whole + (ip_denom * 0.1)
kpbb = f'{p["k/bb"]:.1f}'
era = f'{p["era"]:.2f}'
whip = f'{p["whip"]:.2f}'
pitching_string = f'```\n' \
f' W-L SV ERA WHIP\n' \
f'{p["win"]: >2}-{p["loss"]: <2} {p["save"]: >2} {era: >5} {whip: >4}\n``````\n' \
f' IP SO K/BB WPA\n' \
f'{ips: >5} {p["so"]: ^3} {kpbb: ^4} {p["wpa"]:.3f}\n```'
if batting_string and batter_priority:
embed.add_field(name='Batting Stats', value=batting_string, inline=False)
if pitching_string:
embed.add_field(name='Pitching Stats', value=pitching_string, inline=False)
if batting_string and not batter_priority:
embed.add_field(name='Batting Stats', value=batting_string, inline=False)
return embed
def get_player_url(player, which="sba"):
stub_name = player["name"].replace(" ", "%20")
if which == 'bbref':
if player['bbref_id'] is not None:
br_id = player['bbref_id']
return f'https://www.baseball-reference.com/players/{br_id[0]}/{br_id}.shtml'
else:
return f'https://www.baseball-reference.com/search/search.fcgi?search={stub_name}'
else:
return f'{SBA_BASE_URL}/players/{player["season"]}/{stub_name}'
def get_channel(ctx, name):
channel = discord.utils.get(
ctx.guild.text_channels,
name=name
)
if channel:
return channel
return None
async def create_channel(
ctx, channel_name: str, category_name: str, everyone_send: bool = False, everyone_read: bool = True,
read_send_members: list = None, read_send_roles: list = None, read_only_roles: list = None,
read_only_pokemon: bool = True):
this_category = discord.utils.get(ctx.guild.categories, name=category_name)
if not this_category:
raise ValueError(f'I couldn\'t find a category named **{category_name}**')
overwrites = {
ctx.guild.me: discord.PermissionOverwrite(read_messages=True, send_messages=True),
ctx.guild.default_role: discord.PermissionOverwrite(read_messages=everyone_read, send_messages=everyone_send)
}
if read_send_members:
for member in read_send_members:
overwrites[member] = discord.PermissionOverwrite(read_messages=True, send_messages=True)
if read_send_roles:
for role in read_send_roles:
overwrites[role] = discord.PermissionOverwrite(read_messages=True, send_messages=True)
if read_only_roles:
for role in read_only_roles:
overwrites[role] = discord.PermissionOverwrite(read_messages=True, send_messages=False)
if read_only_pokemon:
poke_role = get_role(ctx, 'Pokétwo')
overwrites[poke_role] = discord.PermissionOverwrite(read_messages=True, send_messages=False)
this_channel = await ctx.guild.create_text_channel(
channel_name,
overwrites=overwrites,
category=this_category
)
logging.info(f'Creating channel ({channel_name}) in ({category_name})')
return this_channel
async def get_major_team(team):
if team['abbrev'][-3:] == 'MiL':
return await get_team_by_abbrev(team['abbrev'][:-3], team['season'])
elif team['abbrev'][-2:] == 'IL':
return await get_team_by_abbrev(team['abbrev'][:-2], team['season'])
else:
return team
async def react_and_reply(ctx, reaction, message):
await ctx.message.add_reaction(reaction)
await ctx.send(message)
async def toggle_draft_sheet() -> None:
sheets = pygsheets.authorize(service_file='storage/major-domo-service-creds.json')
this_sheet = sheets.open_by_key(SBA_SEASON6_DRAFT_KEY)
my_cards = this_sheet.worksheet_by_title('BUTTON')
logging.info(f'Toggling the draft button...')
my_cards.update_value(
'B3', 'FALSE'
)
await asyncio.sleep(1)
my_cards.update_value(
'B3', 'TRUE'
)
async def log_injury(current: dict, inj_dict: dict) -> None:
sheets = pygsheets.authorize(service_file='storage/major-domo-service-creds.json')
this_sheet = sheets.open_by_key(SBA_ROSTER_KEY)
injury_sheet = this_sheet.worksheet_by_title('Injury Log')
logging.info(f'updating values')
try:
injury_sheet.update_values(
crange=f'A{current["injury_count"]+2}',
values=[[
datetime.datetime.now().strftime('%Y-%m-%d, %H:%M:%S'), inj_dict['player']['name'], inj_dict['type'],
inj_dict['player']['team']['abbrev'], current['week'], inj_dict['current_game'],
inj_dict['injury_length']
]]
)
except Exception as e:
logging.error(f'log_injury sheets: {e}')
raise Exception(e)
def get_pos_abbrev(pos_name):
if pos_name == 'Catcher':
return 'C'
elif pos_name == 'First Base':
return '1B'
elif pos_name == 'Second Base':
return '2B'
elif pos_name == 'Third Base':
return '3B'
elif pos_name == 'Shortstop':
return 'SS'
elif pos_name == 'Left Field':
return 'LF'
elif pos_name == 'Center Field':
return 'CF'
elif pos_name == 'Right Field':
return 'RF'
elif pos_name == 'Pitcher':
return 'P'
elif pos_name == 'Designated Hitter':
return 'DH'
elif pos_name == 'Pinch Hitter':
return 'PH'
else:
raise KeyError(f'{pos_name} is not a recognized position name')
def random_gif(search_term: str):
req_url = f'https://api.giphy.com/v1/gifs/translate?s={search_term}&api_key=H86xibttEuUcslgmMM6uu74IgLEZ7UOD'
resp = requests.get(req_url, timeout=3)
if resp.status_code == 200:
data = resp.json()
if 'trump' in data['data']['title']:
return random_conf_gif()
else:
return data['data']['url']
else:
logging.warning(resp.text)
raise ValueError(f'DB: {resp.text}')
def new_rand_conf_gif():
return random_gif('all done')
def random_from_list(data_list: list):
item = data_list[random.randint(0, len(data_list) - 1)]
logging.info(f'random_from_list: {item}')
return item
def get_team_url(this_team):
return f'https://sba.manticorum.com/teams/{this_team["season"]}/{this_team["abbrev"]}'