Initial commit
This commit is contained in:
parent
ba30dad5a4
commit
181689fb61
180
cogs/admins.py
Normal file
180
cogs/admins.py
Normal file
@ -0,0 +1,180 @@
|
||||
import copy
|
||||
|
||||
from helpers import *
|
||||
from db_calls import *
|
||||
|
||||
import math
|
||||
import pygsheets
|
||||
|
||||
from discord.ext import commands, tasks
|
||||
from discord import app_commands
|
||||
|
||||
|
||||
class Admins(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
async def cog_command_error(self, ctx, error):
|
||||
await ctx.send(f'{error}')
|
||||
|
||||
@commands.command(name='current', help='Current db info')
|
||||
@commands.is_owner()
|
||||
async def current_command(self, ctx):
|
||||
current = await get_current()
|
||||
current_string = ''
|
||||
|
||||
for x in current:
|
||||
current_string += f'{x}: {current[x]}\n'
|
||||
|
||||
await ctx.send(current_string)
|
||||
|
||||
@commands.command(name='blast', help='Megaphone')
|
||||
@commands.is_owner()
|
||||
async def blast_command(self, ctx, channel_name, *, message):
|
||||
await send_to_channel(self.bot, channel_name, message)
|
||||
await ctx.send(random_conf_gif())
|
||||
|
||||
@app_commands.command(name='blast', description='Send a message')
|
||||
@app_commands.guilds(discord.Object(id=os.environ.get('GUILD_ID')))
|
||||
@app_commands.checks.has_any_role('Da Commish')
|
||||
async def blast_slash(
|
||||
self, interaction: discord.Interaction, channel: discord.TextChannel, msg_content: str = None,
|
||||
embed_title: str = None, embed_field_name: str = None, image_url: str = None, color_hex: str = None):
|
||||
current = await get_current()
|
||||
|
||||
try:
|
||||
embed = None
|
||||
if embed_title:
|
||||
embed = discord.Embed(
|
||||
title=embed_title,
|
||||
color=int(color_hex, 16) if color_hex is not None else int('0xa5fffc', 16)
|
||||
)
|
||||
embed.set_footer(text=f'SBa Season {current["season"]}', icon_url=LOGO)
|
||||
embed.set_image(url=image_url)
|
||||
if embed_field_name:
|
||||
embed.add_field(
|
||||
name=embed_field_name if embed_field_name is not None else "** **",
|
||||
value=msg_content
|
||||
)
|
||||
await channel.send(content=None, embed=embed)
|
||||
await interaction.response.send_message(content=random_conf_gif())
|
||||
return
|
||||
|
||||
await channel.send(content=msg_content)
|
||||
except Exception as e:
|
||||
logging.error(f'Error blasting a message: {type(e)}: {e}')
|
||||
await interaction.response.send_message(content=f'Uh oh\n\n{type(e)}: {e}')
|
||||
|
||||
@commands.command(name='sendstats', help='all, batting, pitching')
|
||||
@commands.is_owner()
|
||||
async def send_stats_command(self, ctx, which='all'):
|
||||
trans_cog = self.bot.get_cog('Transactions')
|
||||
await trans_cog.send_stats_to_sheets(which=which)
|
||||
|
||||
@commands.command(name='test', hidden=True)
|
||||
@commands.is_owner()
|
||||
async def test_command(self, ctx):
|
||||
current = await get_current()
|
||||
week_num = f'Week {current["week"]}'
|
||||
stars = f'{"":*<32}'
|
||||
freeze_message = f'```\n' \
|
||||
f'{stars}\n'\
|
||||
f'{week_num: >9} Freeze Period Begins\n' \
|
||||
f'{stars}\n```'
|
||||
|
||||
await send_to_channel(self.bot, 'general', freeze_message)
|
||||
|
||||
@commands.command(name='sendmoves', help='Send moves to sheets')
|
||||
@commands.is_owner()
|
||||
async def send_moves_command(self, ctx):
|
||||
current = await get_current()
|
||||
await ctx.send('Authenticating with sheets...')
|
||||
sheets = pygsheets.authorize(service_file='storage/major-domo-service-creds.json')
|
||||
trans_tab = sheets.open_by_key(SBA_ROSTER_KEY).worksheet_by_title('Transactions')
|
||||
await ctx.send('Collecting transactions...')
|
||||
all_vals = []
|
||||
all_moves = await get_transactions(
|
||||
season=current['season'],
|
||||
timeout=30
|
||||
)
|
||||
await ctx.send(f'Processing transactions ({len(all_moves)} found)...')
|
||||
total_moves = len(all_moves)
|
||||
|
||||
counter = 0
|
||||
for move in [*all_moves.values()]:
|
||||
all_vals.insert(
|
||||
0,
|
||||
[
|
||||
move['player']['name'],
|
||||
move['oldteam']['sname'],
|
||||
move['newteam']['sname'],
|
||||
move['week'],
|
||||
total_moves + 416 - counter
|
||||
]
|
||||
)
|
||||
counter += 1
|
||||
logging.warning(f'all_vals samples:\n0: {all_vals[0]}\n100: {all_vals[100]}\n1000: {all_vals[1000]}\n'
|
||||
f'2000: {all_vals[2000]}')
|
||||
|
||||
await ctx.send('Sending transactions to sheets...')
|
||||
try:
|
||||
trans_tab.update_values(
|
||||
crange=f'A420',
|
||||
values=all_vals
|
||||
)
|
||||
await ctx.send('All done!')
|
||||
except Exception as e:
|
||||
await ctx.send('Failed sending to sheets')
|
||||
|
||||
@commands.command(name='xpick', help='Expansion pick')
|
||||
@commands.is_owner()
|
||||
async def expansion_pick_command(self, ctx, team_abbrev, *, name):
|
||||
current = await get_current()
|
||||
player_cog = self.bot.get_cog('Players')
|
||||
player_name = await fuzzy_player_search(ctx, ctx.channel, self.bot, name, player_cog.player_list.keys())
|
||||
player = await get_one_player(player_name)
|
||||
team = await get_one_team(team_abbrev)
|
||||
old_team = copy.deepcopy(player["team"])
|
||||
|
||||
if not team:
|
||||
await ctx.send(f'Who the fuck is **{team_abbrev}**? Get your shit together - it\'s DRAFT TIME!!!')
|
||||
return
|
||||
|
||||
if old_team['id'] == 99:
|
||||
await ctx.send(f'Tell that bastard they\'re an idiot. {player["name"]} is a Free Agent.')
|
||||
return
|
||||
|
||||
await patch_player(player['id'], team_id=team['id'])
|
||||
await ctx.send(content=None, embed=await get_player_embed(await get_one_player(player['id']), current))
|
||||
await send_to_channel(
|
||||
self.bot,
|
||||
's4-draft-picks',
|
||||
f'Expansion Draft: {await get_emoji(ctx, team["sname"])}{team["sname"]} select **{player["name"]}** from '
|
||||
f'{await get_emoji(ctx, old_team["sname"])}{old_team["abbrev"]}'
|
||||
)
|
||||
|
||||
@commands.command(name='injimport')
|
||||
@commands.is_owner()
|
||||
async def injury_import_command(self, ctx):
|
||||
sheets = pygsheets.authorize(service_file='storage/major-domo-service-creds.json')
|
||||
inj_tab = sheets.open_by_key('1uKRf7YwTcEfp8D7gUutQRwnOHW37hl6XcBbtqw3PbN4').worksheet_by_title('Sheet1')
|
||||
raw_data = inj_tab.get_values('A1', 'B545')
|
||||
|
||||
for line in raw_data:
|
||||
player = await get_one_player(line[0])
|
||||
await patch_player(player['id'], pitcher_injury=line[1])
|
||||
|
||||
@commands.command(name='setdemweek', help='Set player\'s demotion week')
|
||||
@commands.is_owner()
|
||||
async def set_dem_week_command(self, ctx, week_num, *, player_name):
|
||||
player_cog = self.bot.get_cog('Players')
|
||||
player_name = await fuzzy_player_search(ctx, ctx.channel, self.bot, player_name, player_cog.player_list.keys())
|
||||
player = await get_one_player(player_name)
|
||||
|
||||
await patch_player(player['id'], demotion_week=week_num)
|
||||
await ctx.send(random_conf_gif())
|
||||
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(Admins(bot))
|
||||
1419
cogs/dice.py
Normal file
1419
cogs/dice.py
Normal file
File diff suppressed because it is too large
Load Diff
1075
cogs/draft.py
Normal file
1075
cogs/draft.py
Normal file
File diff suppressed because it is too large
Load Diff
422
cogs/fun.py
Normal file
422
cogs/fun.py
Normal file
@ -0,0 +1,422 @@
|
||||
import math
|
||||
|
||||
from helpers import *
|
||||
import discord
|
||||
|
||||
from peewee import *
|
||||
from datetime import datetime, timedelta
|
||||
from discord.ext import commands, tasks
|
||||
|
||||
db = SqliteDatabase(
|
||||
'storage/sba_is_fun.db',
|
||||
pragmas={
|
||||
'journal_mode': 'wal',
|
||||
'cache_size': -1 * 64000,
|
||||
'synchronous': 0
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class Creator(Model):
|
||||
name = CharField()
|
||||
discordid = IntegerField()
|
||||
|
||||
class Meta:
|
||||
database = db
|
||||
|
||||
|
||||
class Command(Model):
|
||||
name = CharField()
|
||||
message = CharField()
|
||||
creator = ForeignKeyField(Creator)
|
||||
createtime = DateTimeField()
|
||||
last_used = DateTimeField()
|
||||
sent_warns = IntegerField(default=0)
|
||||
|
||||
class Meta:
|
||||
database = db
|
||||
|
||||
|
||||
class Roles(Model):
|
||||
name = CharField(unique=True)
|
||||
enabled = BooleanField(default=True)
|
||||
|
||||
class Meta:
|
||||
database = db
|
||||
|
||||
|
||||
class Fun(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
db.create_tables([Creator, Command, Roles])
|
||||
db.close()
|
||||
self.daily_check.start()
|
||||
|
||||
@tasks.loop(hours=20)
|
||||
async def daily_check(self):
|
||||
try:
|
||||
# logging.info(f'trying to start cc check')
|
||||
guild = self.bot.get_guild(int(os.environ.get('GUILD_ID')))
|
||||
if not guild:
|
||||
# logging.info(f'no guild found for cc check')
|
||||
await asyncio.sleep(15)
|
||||
guild = self.bot.get_guild(int(os.environ.get('GUILD_ID')))
|
||||
if not guild:
|
||||
logging.error(f'Fun cog could not access guild')
|
||||
return
|
||||
except Exception as e:
|
||||
logging.error(f'Could not run daily_check: {e}')
|
||||
return
|
||||
|
||||
# <discordid> = {'member': <discord member>, 'commands': [(<command.name>, <command.message>)]}
|
||||
del_notifs = {}
|
||||
del_counter = 0
|
||||
# <discordid> = {'member': <discord member>, 'commands': [(<command.name>, <command.message>)]}
|
||||
warn_notifs = {}
|
||||
now = datetime.now()
|
||||
for x in Command.select():
|
||||
# Final check / deleted
|
||||
if x.last_used + timedelta(days=90) < now:
|
||||
logging.warning(f'Deleting `!cc {x.name}`')
|
||||
owner = guild.get_member(x.creator.discordid)
|
||||
if owner:
|
||||
if owner.id not in del_notifs:
|
||||
del_notifs[owner.id] = {'member': owner, 'commands': [(x.name, x.message)]}
|
||||
else:
|
||||
del_notifs[owner.id]['commands'].append((x.name, x.message))
|
||||
|
||||
# x.delete_instance()
|
||||
del_counter += 1
|
||||
|
||||
elif x.last_used + timedelta(days=60) < now and (x.sent_warns is None or x.sent_warns == 0):
|
||||
logging.warning(f'Warning for `!cc {x.name}`')
|
||||
x.sent_warns = 1
|
||||
x.save()
|
||||
owner = guild.get_member(x.creator.discordid)
|
||||
if owner:
|
||||
if owner.id not in warn_notifs:
|
||||
warn_notifs[owner.id] = {'member': owner, 'commands': [(x.name, x.message)]}
|
||||
else:
|
||||
warn_notifs[owner.id]['commands'].append((x.name, x.message))
|
||||
|
||||
# else:
|
||||
# logging.warning(
|
||||
# f'Command <!cc {x.name}> last used {x.last_used} / delta: {now - x.last_used} \n/>60 days: '
|
||||
# f'{x.last_used + timedelta(days=60) < now} / sent_warns: {x.sent_warns}'
|
||||
# )
|
||||
|
||||
db.close()
|
||||
logging.info(f'deletions: {del_notifs}\nwarnings: {warn_notifs}')
|
||||
|
||||
for member in del_notifs:
|
||||
plural = len(del_notifs[member]["commands"]) > 1
|
||||
msg_content = f'Yo, it\'s cleanup time. I am deleting the following custom ' \
|
||||
f'command{"s" if plural else ""}:\n\n'
|
||||
for x in del_notifs[member]["commands"]:
|
||||
msg_content += f'`!cc {x[0]}` - {x[1]}\n'
|
||||
await del_notifs[member]['member'].send(msg_content)
|
||||
|
||||
for member in warn_notifs:
|
||||
plural = len(warn_notifs[member]["commands"]) > 1
|
||||
msg_content = f'Heads up, the following custom ' \
|
||||
f'command{"s" if plural else ""} will be deleted next month if ' \
|
||||
f'{"they are" if plural else "it is"} not used:\n\n'
|
||||
for x in warn_notifs[member]["commands"]:
|
||||
msg_content += f'`!cc {x[0]}` - {x[1]}\n'
|
||||
await warn_notifs[member]['member'].send(msg_content)
|
||||
|
||||
logging.info(f'Deleted {del_counter} commands; sent deletion notifications to {len(del_notifs)} users; '
|
||||
f'sent warnings to {len(warn_notifs)} users')
|
||||
|
||||
async def cog_command_error(self, ctx, error):
|
||||
await ctx.send(f'{error}')
|
||||
|
||||
@commands.command(name='cc', help='Run custom custom command')
|
||||
async def custom_command(self, ctx, command):
|
||||
chosen = Command.get_or_none(fn.Lower(Command.name) == command.lower())
|
||||
if not chosen:
|
||||
# Error gif
|
||||
# await ctx.send('https://tenor.com/blQnd.gif')
|
||||
|
||||
# Schitt's Creek 'what's that' gif
|
||||
# await ctx.send('https://media.giphy.com/media/l0HUhFZx6q0hsPtHq/giphy.gif')
|
||||
|
||||
# Kermit lost gif
|
||||
await ctx.send('https://tenor.com/6saQ.gif')
|
||||
else:
|
||||
await ctx.send(chosen.message)
|
||||
chosen.last_used = datetime.now()
|
||||
chosen.sent_warns = 0
|
||||
chosen.save()
|
||||
|
||||
db.close()
|
||||
|
||||
@commands.command(name='about', help='Who made the custom command')
|
||||
async def about_command(self, ctx, command):
|
||||
chosen = Command.get_or_none(fn.Lower(Command.name) == command.lower())
|
||||
if not chosen:
|
||||
await ctx.send('https://tenor.com/blQnd.gif')
|
||||
|
||||
embed = discord.Embed(title=f'About {chosen.name.title()}', color=0xFFFF00)
|
||||
embed.add_field(name=f'Creator', value=f'{chosen.creator.name}', inline=False)
|
||||
embed.add_field(name='Creation Date', value=f'{chosen.createtime}', inline=False)
|
||||
embed.add_field(name='Message', value=f'{chosen.message}', inline=False)
|
||||
|
||||
await ctx.send(content=None, embed=embed)
|
||||
db.close()
|
||||
|
||||
@commands.command(name='newcc', help='Create a new custom command')
|
||||
@commands.has_any_role(SBA_PLAYERS_ROLE_NAME, 'Paper Dynasty Players')
|
||||
async def new_custom_command(self, ctx, name, *, message):
|
||||
time = datetime.now()
|
||||
command = name
|
||||
comm_message = message
|
||||
|
||||
chosen = Command.get_or_none(fn.Lower(Command.name) == command.lower())
|
||||
if chosen:
|
||||
await ctx.send('There is already a command with that name!')
|
||||
return
|
||||
|
||||
embed = discord.Embed(title='Is this what you want?', color=0x91329F)
|
||||
embed.add_field(name='Command Name', value=command, inline=False)
|
||||
embed.add_field(name='Message', value=comm_message, inline=False)
|
||||
|
||||
await ctx.send(content=None, embed=embed)
|
||||
|
||||
view = Confirm(responders=[ctx.author])
|
||||
question = await ctx.send('Should I create this for you?', view=view)
|
||||
await view.wait()
|
||||
|
||||
if not view.value:
|
||||
await question.edit(content='You keep thinking on it.', view=None)
|
||||
return
|
||||
|
||||
this_person = Creator.get_or_none(Creator.discordid == ctx.author.id)
|
||||
if not this_person:
|
||||
this_person = Creator(name=f'{ctx.author.name}', discordid=f'{ctx.author.id}')
|
||||
this_person.save()
|
||||
|
||||
this_command = Command(name=command, message=comm_message, createtime=time, creator=this_person, last_used=time)
|
||||
if this_command.save() == 1:
|
||||
await question.edit(content=f'`!cc {this_command.name}` is now a thing!', view=None)
|
||||
else:
|
||||
await question.edit(content='Hmm...I couldn\'t add that. I might need a grown up to help.', view=None)
|
||||
|
||||
db.close()
|
||||
|
||||
@commands.command(name='delcc', help='Delete a custom command')
|
||||
@commands.has_any_role(SBA_PLAYERS_ROLE_NAME, 'Paper Dynasty Players')
|
||||
async def delete_custom_command(self, ctx, name):
|
||||
this_command = Command.get_or_none(fn.Lower(Command.name) == name.lower())
|
||||
if not this_command:
|
||||
await ctx.send('I couldn\'t find that command, sorry.')
|
||||
return
|
||||
|
||||
if this_command.creator.discordid != ctx.author.id and ctx.author.id != self.bot.owner_id:
|
||||
await ctx.send('Looks like this isn\'t your command to delete.')
|
||||
return
|
||||
|
||||
embed = discord.Embed(title='Do you want to delete this command?', color=0x91329F)
|
||||
embed.add_field(name='Command Name', value=this_command.name, inline=False)
|
||||
embed.add_field(name='Message', value=this_command.message, inline=False)
|
||||
|
||||
view = Confirm(responders=[ctx.author])
|
||||
question = await ctx.send(content=None, embed=embed, view=view)
|
||||
await view.wait()
|
||||
|
||||
if not view.value:
|
||||
await question.edit(content='It stays for now.', view=None)
|
||||
return
|
||||
|
||||
if this_command.delete_instance() == 1:
|
||||
await ctx.send('He gone!')
|
||||
else:
|
||||
await ctx.send('Welp. That didn\'t work. Go complain to an adult, I guess.')
|
||||
|
||||
db.close()
|
||||
|
||||
@commands.command(name='allcc', help='Show all custom commands')
|
||||
async def show_custom_commands(self, ctx, page=1):
|
||||
def get_embed(this_page):
|
||||
this_embed = discord.Embed(title=f'All Custom Commands', color=0x2F939F)
|
||||
column_one = ''
|
||||
column_two = ''
|
||||
all_commands = Command.select().paginate(this_page, 40).order_by(Command.name)
|
||||
for x in range(20):
|
||||
try:
|
||||
column_one += f'**{all_commands[x].name}** by {all_commands[x].creator.name}\n'
|
||||
except Exception as e:
|
||||
logging.error(f'Error building !allcc embed: {e}')
|
||||
break
|
||||
this_embed.add_field(name=f'{(this_page - 1) * 40 + 1}-{this_page * 40 - 20}', value=column_one)
|
||||
|
||||
for x in range(20, 40):
|
||||
try:
|
||||
column_two += f'**{all_commands[x].name}** by {all_commands[x].creator.name}\n'
|
||||
except Exception as e:
|
||||
logging.error(f'Error building !allcc embed: {e}')
|
||||
break
|
||||
if len(column_two) > 0:
|
||||
this_embed.add_field(name=f'{(this_page - 1) * 40 + 21}-{this_page * 40}', value=column_two)
|
||||
|
||||
return this_embed
|
||||
|
||||
page_num = page
|
||||
total_commands = Command.select(Command.id)
|
||||
last_page = math.ceil(total_commands.count()/40)
|
||||
|
||||
if page_num > last_page:
|
||||
await ctx.send(f'The max page number is {last_page}; going there now!')
|
||||
page_num = last_page
|
||||
|
||||
embed = get_embed(page_num)
|
||||
embed.description = f'Page {page_num} / {last_page}'
|
||||
view = Pagination(responders=[ctx.author])
|
||||
resp_message = await ctx.send(content=None, embed=embed, view=view)
|
||||
|
||||
while True:
|
||||
await view.wait()
|
||||
|
||||
if view.value:
|
||||
logging.info(f'got a value: {view.value}')
|
||||
if view.value == 'left':
|
||||
page_num = page_num - 1 if page_num > 1 else last_page
|
||||
if view.value == 'right':
|
||||
page_num = page_num + 1 if page_num <= last_page else 1
|
||||
view.value = None
|
||||
else:
|
||||
await resp_message.edit(content=None, embed=embed, view=None)
|
||||
break
|
||||
|
||||
# await resp_message.edit(content=None, embed=embed, view=None)
|
||||
embed = get_embed(page_num)
|
||||
embed.description = f'Page {page_num} / {last_page}'
|
||||
view = Pagination(responders=[ctx.author])
|
||||
await resp_message.edit(content=None, embed=embed, view=view)
|
||||
|
||||
db.close()
|
||||
|
||||
@commands.command(name='mycc', aliases=['showcc'], help='Show my commands')
|
||||
@commands.has_any_role(SBA_PLAYERS_ROLE_NAME, 'Paper Dynasty Players')
|
||||
async def my_custom_commands(self, ctx):
|
||||
this_creator = Creator.get_or_none(Creator.discordid == ctx.author.id)
|
||||
|
||||
if not this_creator:
|
||||
await ctx.send('It doesn\'t look like you\'ve created any custom commands. Try it out by running the '
|
||||
'!help newcc for the command syntax!')
|
||||
return
|
||||
|
||||
all_commands = Command.select().join(Creator).where(Command.creator == this_creator)
|
||||
|
||||
if all_commands.count() == 0:
|
||||
await ctx.send('It doesn\'t look like you\'ve created any custom commands. Try it out by running the '
|
||||
'!help newcc for the command syntax!')
|
||||
return
|
||||
|
||||
comm_message = ''
|
||||
for x in all_commands:
|
||||
comm_message += f'{x.name}\n'
|
||||
|
||||
embed = discord.Embed(title=f'{ctx.author.name}\'s Commands', color=0x2F939F)
|
||||
embed.add_field(name=f'Command Names', value=comm_message, inline=False)
|
||||
|
||||
await ctx.send(content=None, embed=embed)
|
||||
|
||||
db.close()
|
||||
|
||||
# @commands.command(name='showcc', help='Show one person\'s custom commands')
|
||||
# @commands.has_any_role(SBA_PLAYERS_ROLE_NAME, 'Paper Dynasty Players')
|
||||
# async def show_cc_command(self, ctx, ):
|
||||
|
||||
# @commands.command(name='role', help='Toggle role')
|
||||
# async def toggle_role_command(self, ctx, *, role_name):
|
||||
# all_roles = [x.name for x in Roles.select().where(Roles.enabled)]
|
||||
#
|
||||
# async def toggle_role(full_role):
|
||||
# if full_role in ctx.author.roles:
|
||||
# await ctx.author.remove_roles(full_role)
|
||||
# else:
|
||||
# await ctx.author.add_roles(full_role)
|
||||
#
|
||||
# if len(role_name) < 4:
|
||||
# await ctx.send('https://thumbs.gfycat.com/FrayedUnequaledGnat-size_restricted.gif')
|
||||
# await ctx.send(f'What even is **{role_name}**...')
|
||||
# db.close()
|
||||
# return
|
||||
#
|
||||
# for name in all_roles:
|
||||
# if role_name.lower() in name.lower():
|
||||
# try:
|
||||
# this_role = discord.utils.get(ctx.guild.roles, name=name)
|
||||
# await toggle_role(this_role)
|
||||
# await ctx.send(random_conf_gif())
|
||||
# return
|
||||
# except:
|
||||
# await ctx.send(await get_emoji(ctx, 'fforrespect', False))
|
||||
# await ctx.send('I was not able to assign that role.')
|
||||
# return
|
||||
#
|
||||
# await ctx.send(f'That doesn\'t sound familiar. **{role_name}**...did you make that shit up?')
|
||||
|
||||
# @commands.command(name='showroles', help='Show toggleable roles')
|
||||
# async def show_roles_command(self, ctx):
|
||||
# all_roles = [x.name for x in Roles.select().where(Roles.enabled)]
|
||||
# role_string = '\n- '.join(all_roles)
|
||||
#
|
||||
# embed = get_team_embed('Toggleable Roles', thumbnail=False)
|
||||
# embed.description = 'Run !role <role_name> to toggle the role on or off'
|
||||
# embed.add_field(name='Role Names', value=f'- {role_string}')
|
||||
#
|
||||
# await ctx.send(content=None, embed=embed)
|
||||
|
||||
# @commands.command(name='newrole', aliases=['removerole'], help='Make toggleable role')
|
||||
# @commands.is_owner()
|
||||
# async def make_toggleable_role_command(self, ctx, *, role_name):
|
||||
# this_role = Roles.get_or_none(Roles.name == role_name)
|
||||
#
|
||||
# if not this_role:
|
||||
# # Create the role if it doesn't exist
|
||||
#
|
||||
# this_role = Roles(name=role_name)
|
||||
# this_role.save()
|
||||
# if not discord.utils.get(ctx.guild.roles, name=this_role.name):
|
||||
# await ctx.guild.create_role(name=f'{role_name}', mentionable=True)
|
||||
# else:
|
||||
# # Disable the role
|
||||
#
|
||||
# if this_role.enabled:
|
||||
# this_role.enabled = False
|
||||
# else:
|
||||
# this_role.enabled = True
|
||||
# this_role.save()
|
||||
# this_role = discord.utils.get(ctx.guild.roles, name=this_role.name)
|
||||
#
|
||||
# if this_role:
|
||||
# await this_role.edit(mentionable=False)
|
||||
# else:
|
||||
# await ctx.send('That role doesn\'t exist in the server.')
|
||||
#
|
||||
# await ctx.send(random_conf_gif())
|
||||
|
||||
# @commands.command(name='bulkrole', hidden=True)
|
||||
# @commands.is_owner()
|
||||
# async def bulkrole_command(self, ctx, *roles):
|
||||
# all_roles = []
|
||||
#
|
||||
# for x in roles:
|
||||
# all_roles.append(discord.utils.get(ctx.guild.roles, name=x))
|
||||
#
|
||||
# await ctx.send('On it. This could take a bit.')
|
||||
# time_start = datetime.now()
|
||||
#
|
||||
# async for member in ctx.guild.fetch_members():
|
||||
# logging.warning(f'member: {member}')
|
||||
# await member.add_roles(*all_roles)
|
||||
#
|
||||
# time_end = datetime.now()
|
||||
# await ctx.send(f'All done! That took {time_end - time_start}')
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(Fun(bot))
|
||||
2383
cogs/gameday.py
Normal file
2383
cogs/gameday.py
Normal file
File diff suppressed because it is too large
Load Diff
1256
cogs/gameplay.py
Normal file
1256
cogs/gameplay.py
Normal file
File diff suppressed because it is too large
Load Diff
123
cogs/owner.py
Normal file
123
cogs/owner.py
Normal file
@ -0,0 +1,123 @@
|
||||
import logging
|
||||
import os
|
||||
|
||||
import discord
|
||||
from discord import Object
|
||||
from discord.ext import commands
|
||||
from discord.ext.commands import Greedy, Context
|
||||
from typing import Optional, Literal
|
||||
|
||||
|
||||
class Owner(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
@commands.command(hidden=True)
|
||||
@commands.is_owner()
|
||||
async def load(self, ctx, *, cog: str):
|
||||
try:
|
||||
await self.bot.load_extension(f'cogs.{cog}')
|
||||
logging.warning(f'Loaded {cog}')
|
||||
except Exception as e:
|
||||
await ctx.send(f'**ERROR:** {type(e).__name__} - {e}')
|
||||
else:
|
||||
await ctx.send('**SUCCESS**')
|
||||
|
||||
@commands.command(hidden=True)
|
||||
@commands.is_owner()
|
||||
async def unload(self, ctx, *, cog: str):
|
||||
try:
|
||||
await self.bot.unload_extension(f'cogs.{cog}')
|
||||
logging.warning(f'Unloaded {cog}')
|
||||
except Exception as e:
|
||||
await ctx.send(f'**ERROR:** {type(e).__name__} - {e}')
|
||||
else:
|
||||
await ctx.send('**SUCCESS**')
|
||||
|
||||
@commands.command(hidden=True)
|
||||
@commands.is_owner()
|
||||
async def reload(self, ctx, *, cog: str):
|
||||
try:
|
||||
await self.bot.unload_extension(f'cogs.{cog}')
|
||||
logging.warning(f'Unloaded {cog}')
|
||||
await self.bot.load_extension(f'cogs.{cog}')
|
||||
logging.warning(f'Reloaded {cog}')
|
||||
except Exception as e:
|
||||
await ctx.send(f'**ERROR:** {type(e).__name__} - {e}')
|
||||
else:
|
||||
await ctx.send('**SUCCESS**')
|
||||
|
||||
@commands.command(hidden=True)
|
||||
@commands.is_owner()
|
||||
async def fullreset(self, ctx):
|
||||
cogs = ['players', 'transactions', 'admins', 'dice', 'fun', 'gameday']
|
||||
|
||||
for x in cogs:
|
||||
try:
|
||||
await self.bot.unload_extension(f'cogs.{x}')
|
||||
logging.warning(f'Unloaded {x}')
|
||||
except Exception as e:
|
||||
await ctx.send(f'Failed to unload **{x}**')
|
||||
|
||||
for x in cogs:
|
||||
try:
|
||||
await self.bot.load_extension(f'cogs.{x}')
|
||||
logging.warning(f'Loaded {x}')
|
||||
except Exception as e:
|
||||
await ctx.send(f'Failed to load **{x}**')
|
||||
|
||||
await ctx.send('**SUCCESS**')
|
||||
|
||||
# @commands.command(name='sync', hidden=True)
|
||||
# @commands.is_owner()
|
||||
# async def sync_command(self, ctx, sync_type: str = 'local'):
|
||||
# sync = None
|
||||
# await ctx.send('I will try to sync slash commands...')
|
||||
# try:
|
||||
# if sync_type == 'global':
|
||||
# sync = await self.bot.tree.sync()
|
||||
# else:
|
||||
# sync = await self.bot.tree.sync(guild=discord.Object(os.environ.get('GUILD_ID')))
|
||||
# logging.warning(f'sync: {sync}')
|
||||
# except Exception as e:
|
||||
# logging.error(f'failed to sync: {e}')
|
||||
#
|
||||
# await ctx.send(f'Just ran the sync. Here is the output:\n{sync}')
|
||||
|
||||
@commands.command()
|
||||
@commands.is_owner()
|
||||
async def sync(self, ctx: Context, guilds: Greedy[Object], spec: Optional[Literal['~', "*"]] = None) -> None:
|
||||
"""
|
||||
!sync -> global sync
|
||||
!sync ~ -> sync current guild
|
||||
!sync * -> copies all global app commands to current guild and syncs
|
||||
!sync id_1 id_2 -> syncs guilds with id 1 and 2
|
||||
"""
|
||||
if not guilds:
|
||||
if spec == "~":
|
||||
fmt = await ctx.bot.tree.sync(guild=ctx.guild)
|
||||
elif spec == "*":
|
||||
ctx.bot.tree.copy_global_to(guild=ctx.guild)
|
||||
fmt = await ctx.bot.tree.sync(guild=ctx.guild)
|
||||
else:
|
||||
fmt = await ctx.bot.tree.sync()
|
||||
|
||||
await ctx.send(
|
||||
f"Synced {len(fmt)} commands {'globally' if spec is None else 'to the current guild.'}"
|
||||
)
|
||||
return
|
||||
|
||||
fmt = 0
|
||||
for guild in guilds:
|
||||
try:
|
||||
await ctx.bot.tree.sync(guild=guild)
|
||||
except discord.HTTPException:
|
||||
pass
|
||||
else:
|
||||
fmt += 1
|
||||
|
||||
await ctx.send(f"Synced the tree to {fmt}/{len(guilds)} guilds.")
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(Owner(bot))
|
||||
2967
cogs/players.py
Normal file
2967
cogs/players.py
Normal file
File diff suppressed because it is too large
Load Diff
1979
cogs/transactions.py
Normal file
1979
cogs/transactions.py
Normal file
File diff suppressed because it is too large
Load Diff
1099
db_calls.py
Normal file
1099
db_calls.py
Normal file
File diff suppressed because it is too large
Load Diff
1049
db_calls_gameday.py
Normal file
1049
db_calls_gameday.py
Normal file
File diff suppressed because it is too large
Load Diff
1196
db_calls_gameplay.py
Normal file
1196
db_calls_gameplay.py
Normal file
File diff suppressed because it is too large
Load Diff
42
gameplay_helpers.py
Normal file
42
gameplay_helpers.py
Normal file
@ -0,0 +1,42 @@
|
||||
from db_calls_gameplay import StratGame, StratPlay, StratLineup, StratManagerAi, patch_play, advance_runners, \
|
||||
complete_play
|
||||
|
||||
|
||||
def single_onestar(this_play: StratPlay, comp_play: bool = True):
|
||||
patch_play(this_play.id, locked=True)
|
||||
advance_runners(this_play.id, num_bases=1)
|
||||
patch_play(this_play.id, pa=1, ab=1, hit=1)
|
||||
if comp_play:
|
||||
complete_play(this_play.id, batter_to_base=1)
|
||||
|
||||
|
||||
def single_wellhit(this_play: StratPlay, comp_play: bool = True):
|
||||
patch_play(this_play.id, locked=True)
|
||||
advance_runners(this_play.id, num_bases=2)
|
||||
patch_play(this_play.id, pa=1, ab=1, hit=1)
|
||||
if comp_play:
|
||||
complete_play(this_play.id, batter_to_base=1)
|
||||
|
||||
|
||||
def double_twostar(this_play: StratPlay, comp_play: bool = True):
|
||||
patch_play(this_play.id, locked=True)
|
||||
advance_runners(this_play.id, num_bases=2)
|
||||
patch_play(this_play.id, pa=1, ab=1, hit=1, double=1)
|
||||
if comp_play:
|
||||
complete_play(this_play.id, batter_to_base=2)
|
||||
|
||||
|
||||
def double_threestar(this_play: StratPlay, comp_play: bool = True):
|
||||
patch_play(this_play.id, locked=True)
|
||||
advance_runners(this_play.id, num_bases=3)
|
||||
patch_play(this_play.id, pa=1, ab=1, hit=1, double=1)
|
||||
if comp_play:
|
||||
complete_play(this_play.id, batter_to_base=2)
|
||||
|
||||
|
||||
def triple(this_play: StratPlay, comp_play: bool = True):
|
||||
patch_play(this_play.id, locked=True)
|
||||
advance_runners(this_play.id, num_bases=3)
|
||||
patch_play(this_play.id, pa=1, ab=1, hit=1, triple=1)
|
||||
if comp_play:
|
||||
complete_play(this_play.id, batter_to_base=3)
|
||||
982
helpers.py
Normal file
982
helpers.py
Normal file
@ -0,0 +1,982 @@
|
||||
import datetime
|
||||
|
||||
import pygsheets
|
||||
|
||||
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 = 7
|
||||
PD_SEASON = 4
|
||||
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://sombaseball.ddns.net'
|
||||
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_STANDINGS_URL = f'{SBA_BASE_URL}/standings'
|
||||
SBA_SCHEDULE_URL = f'{SBA_BASE_URL}/schedule'
|
||||
SBA_IMAGE_URL = f'{SBA_BASE_URL}/static/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]
|
||||
|
||||
LOGO = 'https://sombaseball.ddns.net/static/images/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.'
|
||||
},
|
||||
'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 Pagination(discord.ui.View):
|
||||
def __init__(self, responders: list):
|
||||
super().__init__()
|
||||
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.grey)
|
||||
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.grey)
|
||||
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',
|
||||
]
|
||||
|
||||
|
||||
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):
|
||||
"""
|
||||
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()
|
||||
|
||||
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([ctx.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 6', 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):
|
||||
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='Current Team', value=player['team']['sname'])
|
||||
|
||||
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)
|
||||
|
||||
player_trans = await get_transactions(
|
||||
current['season'],
|
||||
week_start=current['week'],
|
||||
week_end=current['week'] + 1,
|
||||
player_id=player['id']
|
||||
)
|
||||
|
||||
for x in player_trans:
|
||||
if player_trans[x]['week'] == current['week']:
|
||||
embed.add_field(name='Last Week', value=f'{player_trans[x]["oldteam"]["sname"]}')
|
||||
if player_trans[x]['week'] == current['week'] + 1:
|
||||
embed.add_field(name='Next Week', value=f'To {player_trans[x]["newteam"]["sname"]}')
|
||||
|
||||
embed.add_field(name='sWAR', value=player['wara'])
|
||||
embed.set_image(url=player['image'])
|
||||
|
||||
player_pages = f'[SBa]({get_player_url(player)}) / ' \
|
||||
f'[BBRef]({get_player_url(player, "bbref")})'
|
||||
embed.add_field(name='Player Page', value=player_pages)
|
||||
positions = get_player_positions(player)
|
||||
if len(positions) > 0:
|
||||
embed.add_field(name=f'Position{"s" if len(positions) > 1 else ""}', value=",".join(positions))
|
||||
if player['team']['abbrev'][-3:].lower() == 'mil':
|
||||
major_team = await get_one_team(player['team']['abbrev'][:-3], season=player['season'])
|
||||
embed.add_field(name='SBa Affiliate', value=major_team['sname'])
|
||||
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['il_return']:
|
||||
embed.add_field(name='IL Return', value=player['il_return'])
|
||||
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 player['demotion_week'] is not None:
|
||||
if player['demotion_week'] > current['week']:
|
||||
embed.add_field(name='Dem Week', value=player["demotion_week"])
|
||||
|
||||
player_awards = await get_awards(season=current['season'], player_name=player['name'])
|
||||
awards = []
|
||||
|
||||
if len(player_awards) > 0:
|
||||
for x in player_awards:
|
||||
awards.append(player_awards[x]['name'])
|
||||
award_string = ', '.join(awards[-3:])
|
||||
if len(awards) > 3:
|
||||
award_string += f', plus {len(awards) - 3} more'
|
||||
embed.add_field(name='Awards', value=award_string, inline=False)
|
||||
|
||||
b = await get_one_battingseason(player['id'])
|
||||
p = await get_one_pitchingseason(player['id'])
|
||||
|
||||
batting_string = None
|
||||
pitching_string = None
|
||||
|
||||
if len(b) > 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```'
|
||||
|
||||
if len(p) > 0:
|
||||
if p['ip'] > 0:
|
||||
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 len(b) > len(p):
|
||||
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 len(p) >= len(b):
|
||||
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':
|
||||
return f'https://www.baseball-reference.com/search/search.fcgi?search={stub_name}'
|
||||
else:
|
||||
return f'https://sombaseball.ddns.net/players?name={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 'Il' in team['abbrev'][len(team['abbrev']) - 2:].lower():
|
||||
return await get_one_team(team['abbrev'][:-2])
|
||||
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 new_rand_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 random_conf_gif()
|
||||
else:
|
||||
return data['data']['url']
|
||||
else:
|
||||
logging.warning(resp.text)
|
||||
raise ValueError(f'DB: {resp.text}')
|
||||
58
majordomo.py
Normal file
58
majordomo.py
Normal file
@ -0,0 +1,58 @@
|
||||
import asyncio
|
||||
import datetime
|
||||
import logging
|
||||
import os
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
|
||||
date = f'{datetime.datetime.now().year}-{datetime.datetime.now().month}-{datetime.datetime.now().day}'
|
||||
log_level = logging.INFO if os.environ.get('LOG_LEVEL') == 'INFO' else 'WARN'
|
||||
logging.basicConfig(
|
||||
filename=f'logs/{date}.log',
|
||||
format='%(asctime)s - majordomo - %(levelname)s - %(message)s',
|
||||
level=log_level
|
||||
)
|
||||
|
||||
COGS = [
|
||||
'cogs.owner',
|
||||
'cogs.players',
|
||||
'cogs.transactions',
|
||||
'cogs.admins',
|
||||
'cogs.dice',
|
||||
'cogs.fun',
|
||||
# 'cogs.gameday',
|
||||
# 'cogs.gameplay'
|
||||
]
|
||||
|
||||
intents = discord.Intents.default()
|
||||
intents.message_content = True
|
||||
intents.members = True
|
||||
bot = commands.Bot(
|
||||
command_prefix='!',
|
||||
intents=intents,
|
||||
description='The Strat-o-matic Bot\nIf you have questions, feel free to contact Cal.',
|
||||
case_insensitive=True,
|
||||
owner_id=258104532423147520
|
||||
)
|
||||
|
||||
|
||||
@bot.event
|
||||
async def on_ready():
|
||||
logging.info('Logged in as:')
|
||||
logging.info(bot.user.name)
|
||||
logging.info(bot.user.id)
|
||||
|
||||
|
||||
async def main():
|
||||
for c in COGS:
|
||||
try:
|
||||
await bot.load_extension(c)
|
||||
logging.info(f'Loaded cog: {c}')
|
||||
except Exception as e:
|
||||
logging.error(f'Failed to load cog: {c}')
|
||||
logging.error(f'{e}')
|
||||
async with bot:
|
||||
await bot.start(os.environ.get('BOT_TOKEN'))
|
||||
|
||||
asyncio.run(main())
|
||||
7
requirements.txt
Normal file
7
requirements.txt
Normal file
@ -0,0 +1,7 @@
|
||||
discord.py @ git+https://github.com/Rapptz/discord.py
|
||||
requests
|
||||
pydantic
|
||||
pygsheets
|
||||
peewee
|
||||
bs4
|
||||
pandas
|
||||
Loading…
Reference in New Issue
Block a user