import math import pydantic import re from discord import app_commands from discord.ext import tasks from db_calls_gameplay import get_one_game from helpers import * from db_calls import * from typing import Literal class BatStat(pydantic.BaseModel): player_id: int team_id: int pos: str pa: int = 0 ab: int = 0 run: int = 0 hit: int = 0 rbi: int = 0 double: int = 0 triple: int = 0 hr: int = 0 bb: int = 0 so: int = 0 hbp: int = 0 sac: int = 0 ibb: int = 0 gidp: int = 0 sb: int = 0 cs: int = 0 bphr: int = 0 bpfo: int = 0 bp1b: int = 0 bplo: int = 0 xba: int = 0 xbt: int = 0 xch: int = 0 xhit: int = 0 error: int = 0 pb: int = 0 sbc: int = 0 csc: int = 0 roba: int = 0 robs: int = 0 raa: int = 0 rto: int = 0 week: int game: int season: int class PitStat(pydantic.BaseModel): player_id: int team_id: int ip: float = 0.0 hit: int = 0 run: int = 0 erun: int = 0 so: int = 0 bb: int = 0 hbp: int = 0 wp: int = 0 balk: int = 0 hr: int = 0 gs: int = 0 win: int = 0 loss: int = 0 hold: int = 0 sv: int = 0 bsv: int = 0 ir: int = 0 irs: int = 0 week: int game: int season: int class Players(commands.Cog): def __init__(self, bot): self.bot = bot self.player_list = {} self.scorecards = {} self.build_master_player_list.start() async def cog_command_error(self, ctx, error): await ctx.send(f'{error}\n\nRun !help to see the command requirements') async def slash_error(self, ctx, error): await ctx.send(f'{error}') @tasks.loop(count=1) async def build_master_player_list(self): current = await get_current() all_players = await get_players(current['season']) self.player_list = {all_players[player]['name'].lower(): all_players[player]['id'] for player in all_players} logging.debug(f'player list: {self.player_list}') logging.warning(f'player list count: {len(self.player_list)}') @staticmethod async def update_injuries(ctx): current = await get_current() injury_log = discord.utils.get(ctx.guild.text_channels, name='injury-log') # Build new messages # inj_by_team = {'Black Bears': [Player Objs], 'Questants': [Player Objs]} # inj_by_week = {'Week 1': [Player Objs], 'Week 2': [Player Objs]} inj_team = {} inj_week = {} all_injuries = await get_players(current['season'], injured=True) for x in all_injuries: player = all_injuries[x] this_team = await get_major_team(player['team']) if this_team['sname'] not in inj_team.keys(): inj_team[this_team['sname']] = [player] else: inj_team[this_team['sname']].append(player) if f'Week {player["il_return"][1:3]}' not in inj_week.keys(): inj_week[f'Week {player["il_return"][1:3]}'] = [player] else: inj_week[f'Week {player["il_return"][1:3]}'].append(player) inj_by_team = dict(sorted(inj_team.items())) inj_by_week = dict(sorted(inj_week.items())) team_embed = discord.Embed(title='Current Injuries by Team') team_embed.description = 'Player Name (Return Date)' team_embed.set_thumbnail(url=LOGO) for team in inj_by_team: team_string = '' for player in inj_by_team[team]: team_string += f'{player["name"]} ({player["il_return"]})\n' team_embed.add_field(name=team, value=team_string) week_embed = discord.Embed(title='Current Injuries by Return Week') week_embed.description = 'Player Name (Return Date)' week_embed.set_thumbnail(url=LOGO) for week in inj_by_week: week_string = '' for player in inj_by_week[week]: week_string += f'{player["name"]} ({player["il_return"]})\n' week_embed.add_field(name=week, value=week_string) # Clear old messages async for message in injury_log.history(limit=25): await message.delete() # Send new messages await injury_log.send(content=None, embed=team_embed) await injury_log.send(content=None, embed=week_embed) @staticmethod def team_stan_line(stan, s_type: str = 'div'): if stan["wins"] + stan["losses"] == 0: winpct = f'{0:.3f}' else: winpct = f'{stan["wins"] / (stan["wins"] + stan["losses"]):.3f}' team_string = f'{stan["team"]["abbrev"]: <4} {stan["wins"]: >2}-{stan["losses"]: <2} {winpct} ' if s_type == 'div': if stan["div_gb"] < 0: gb = stan["div_gb"] if stan["div_gb"] >= 0.0 else f'+{stan["div_gb"] * -1}' else: gb = stan["div_gb"] team_string += f'{gb: >5}' if stan["div_e_num"] is None: team_string += f' -- ' else: e_num = stan["div_e_num"] if stan["div_e_num"] > 0 else 'E' team_string += f' {e_num: >2} ' else: if stan["wc_gb"] is None: # This is a division leader - return nothing and continue return '' else: gb = stan["wc_gb"] if stan["wc_gb"] >= 0.0 else f'+{stan["wc_gb"] * -1}' if stan["wc_e_num"]: e_num = stan["wc_e_num"] elif stan["wc_e_num"] == 0: e_num = 'E' else: e_num = '--' team_string += f'{gb: >5} {e_num: >2} ' team_string += f'{stan["run_diff"]: >4}\n' return team_string @staticmethod async def game_progress(current): this_week = await get_schedule( current['season'], week_start=current['week'], week_end=current['week'] ) results_this_week = await get_results( current['season'], week=current['week'] ) game_count = 0 for x in this_week: game_count += this_week[x]['gamecount'] return {'games_played': len(results_this_week), 'game_count': game_count} @commands.Cog.listener(name='on_message') async def on_message_listener(self, message): # if 'bad man' in message.content: # await message.channel.send( # 'https://cdn.discordapp.com/attachments/619600872782954539/682411826335711268/image0.jpg' # ) if message.author.bot: return tm = message.content.lower() if tm in ['shut up, jack', 'shut up jack']: await message.channel.send('Shut up, Jack') return # elif message.content[-3:] == '...': # await message.channel.send('https://media.tenor.com/images/423f15eef7688d3010c4d83a16902574/tenor.gif') # return elif 'DELIBERAT' in message.content: await message.channel.send('https://tenor.com/view/fbi-swat-jelleton-gif-14190942') elif 'domo sux' in tm or 'domo sucks' in tm or 'fuck domo' in tm or 'fuck you domo' in tm: await message.add_reaction('🖕') elif 'joe momma' in tm or 'joe mama' in tm: await message.channel.send('https://tenor.com/view/shaq-big-dunk-basketball-chris-dudley-shaquille-' 'o-neal-gif-13864249') elif 'i\'m dad' in tm or 'im dad' in tm: await message.channel.send( 'https://tenor.com/view/dad-jokes-aht-aht-dad-jokes-aht-aht-ha-ha-ha-knee-slapper-gif-26152690' ) # elif 'fifa' in tm or 'soccer' in tm or 'world cup' in tm or 'the wc' in tm or 'this wc' in tm or 'futbol' in tm: # randint = random.randint(1, 5) # if randint == 5: # await message.channel.send(f'||{message.content}\n{message.author.name}, apparently||\n\n' # f'Ugh, I can\'t with this soccer talk.') # await message.delete() # else: # await message.channel.send(random_soccer()) if message.channel.name in ['trade-block', 'jacks-trading-post']: count = 0 async for x in message.channel.history(): if x.author.id == message.author.id and x.id != message.id: count += 1 await x.delete() if count > 1: await message.author.send(f'I have deleted your previous {count} trade-block messages to ' f'keep it clean.') elif count == 1: await message.author.send('I deleted your last trade-block message to help keep it clean.') # if len(message.content) == 1 and not message.content.isnumeric() and message.content.lower() != 'k': # logging.info( # f'Found spam from **{message.author.nick}** in **{message.channel.name}**: {message.content}' # ) # if 'shitpost' not in message.channel.name and 'sbb' not in message.channel.name: # await send_to_channel( # self.bot, # 'commissioners-office', # f'Just deleted this message from **{message.author.nick}** in **{message.channel.name}**:' # f'\n\n{message.content}' # ) # await message.delete() # await message.author.send( # f'Hi there. I just deleted your \'{message.content}\' message from #{message.channel.name}. I am ' # f'told to delete 1-character messages due to spam.' # ) @staticmethod def get_standings_embed(current, progress, al_standings, nl_standings): embed = discord.Embed(title=f'Season {current["season"]} | Week {current["week"]} | ' f'{progress["games_played"]}/{progress["game_count"]} games played', color=0xB70000) embed.add_field(name=f'**Full Standings**', value=SBA_STANDINGS_URL, inline=False) embed.add_field(name=f'**American League**', value=al_standings, inline=False) embed.add_field(name=f'**National League**', value=nl_standings, inline=False) return embed @commands.command(name='team', aliases=['roster', 'myboys', 'mybois'], help='Get team overview') async def team_command(self, ctx, *abbrev): current = await get_current() # Get Team if abbrev: team = await get_one_team(abbrev[0]) else: team = await get_team_by_owner(current['season'], ctx.author.id) # Create team embed embed = get_team_embed(f'{team["lname"]} Overview', team) # Get standings if team['abbrev'][-2:].lower() != 'il': try: team_standings = await get_standings(current['season'], team_abbrev=team['abbrev']) if team_standings: overview_string = f'Record: {team_standings["wins"]}-{team_standings["losses"]} ' \ f'({team_standings["run_diff"]} RD)\n' \ f'Pythag Record: {team_standings["pythag_wins"]}-{team_standings["pythag_losses"]}\n' division_string = '' if team_standings['div_gb']: division_string += f'{team_standings["div_gb"]} GB in ' \ f'{team_standings["team"]["division"]["league_abbrev"]} ' \ f'{team_standings["team"]["division"]["division_name"]} / ' \ f'{team_standings["wc_gb"]} GB in ' \ f'{team_standings["team"]["division"]["league_abbrev"]} WC\n' else: division_string += f'1st in {team_standings["team"]["division"]["league_abbrev"]} ' \ f'{team_standings["team"]["division"]["division_name"]}\n' overview_string += division_string overview_string += f'Last 8: ({team_standings["last8_wins"]}-{team_standings["last8_losses"]}) / ' \ f'Streak: {team_standings["streak_wl"].upper()}{team_standings["streak_num"]}' embed.add_field(name=f'{team["sname"]} Overview', value=overview_string, inline=False) except ValueError as e: logging.info(f'Could not pull standings for season {team["season"]} {team["abbrev"]}') # Get player info il_players = None if team['abbrev'][-2:].lower() != 'il': il_players = await get_players(current['season'], team_abbrev=f'{team["abbrev"]}IL', sort='wara-desc') players = await get_players(current['season'], team_abbrev=team['abbrev'], sort='wara-desc') il_wara = 0 active_wara = 0 if il_players: for x in il_players: il_wara += il_players[x]['wara'] if players: count = 0 top_player_string = '' for x in players: if count < 5: top_player_string += f'{players[x]["pos_1"]} {players[x]["name"]} ({players[x]["wara"]:.2f})\n' active_wara += players[x]['wara'] count += 1 embed.add_field(name='Core Players', value=top_player_string) embed.add_field(name='Total sWAR', value=f'{active_wara:.2f}') if il_wara > 0: embed.add_field(name='Injured sWAR', value=f'{il_wara:.2f}') # Get near schedule team_schedule = await get_schedule( current['season'], team_abbrev1=team["abbrev"], week_start=current['week'], week_end=current['week']+2 if current['week']+2 > 0 else 2, ) if team_schedule: this_week_string = '' upcoming_string = '' full_sched = dict(sorted(team_schedule.items(), key=lambda item: item[1]["id"])) for matchup in full_sched: if full_sched[matchup]['hometeam'] == team: opp_record = await get_standings( season=current['season'], team_abbrev=full_sched[matchup]['awayteam']['abbrev'] ) else: opp_record = await get_standings( season=current['season'], team_abbrev=full_sched[matchup]['hometeam']['abbrev'] ) if full_sched[matchup]['week'] == current['week']: if full_sched[matchup]['hometeam'] == team: this_week_string += f'Week {current["week"]}: vs ' \ f'{full_sched[matchup]["awayteam"]["lname"]} ' \ f'({opp_record["wins"]}-{opp_record["losses"]})\n' else: this_week_string += f'Week {current["week"]}: @ {full_sched[matchup]["hometeam"]["lname"]} ' \ f'({opp_record["wins"]}-{opp_record["losses"]})\n' else: if full_sched[matchup]['hometeam'] == team: upcoming_string += f'Week {full_sched[matchup]["week"]}: vs ' \ f'{full_sched[matchup]["awayteam"]["lname"]} ' \ f'({opp_record["wins"]}-{opp_record["losses"]})\n' else: upcoming_string += f'Week {full_sched[matchup]["week"]}: @ ' \ f'{full_sched[matchup]["hometeam"]["lname"]} ' \ f'({opp_record["wins"]}-{opp_record["losses"]})\n' if len(this_week_string) > 0: embed.add_field(name='This Week', value=this_week_string, inline=False) if len(upcoming_string) > 0: embed.add_field(name='Upcoming Schedule', value=upcoming_string, inline=False) # Add roster link embed.add_field( name=f'{team["abbrev"]} Roster Page', value=f'https://sombaseball.ddns.net/teams?abbrev={team["abbrev"]}', inline=False ) await ctx.send(content=None, embed=embed) @commands.command(name='player', aliases=['card'], help='Get player overview') async def player_command(self, ctx, *, name): current = await get_current() name_reg = re.compile(r'(s\d+)* *(.*)', re.IGNORECASE) player_search = name_reg.search(name) logging.info(f'player_search: {player_search}') logging.info(f'player_search.group(): {player_search.group()} / group(1): {player_search.group(1)} ' f'/ group(2): {player_search.group(2)}') # No season is included if not player_search.group(1): player = await get_one_player( await fuzzy_player_search(ctx, ctx.channel, self.bot, name, self.player_list.keys()) ) # Season is included else: season = int(player_search.group(1)[1:]) try: player = await get_one_player(player_search.group(2), season=season) except Exception as e: logging.error(e) async with ctx.typing(): all_players = await get_players(season) all_player_names = {all_players[player]['name'].lower(): all_players[player]['id'] for player in all_players} player = await get_one_player( await fuzzy_player_search(ctx, ctx.channel, self.bot, player_search.group(2).strip(), all_player_names), season=season ) embed = await get_player_embed(player, current, ctx) await ctx.send(content=None, embed=embed) if player['image2']: embed = get_team_embed(f'{player["name"]}', player["team"], thumbnail=False) embed.set_image(url=player['image2']) await ctx.send(content=None, embed=embed) @commands.command(name='career', help='Get player\'s career stats') async def career_command(self, ctx, *, name): # Get BattingCareer b = await get_battingcareer(name) # Get PitchingCareer p = await get_pitchingcareer(name) if not b and not p: await ctx.send('Who? Please splel berter') return player = { 'name': b['name'] if b else p['name'], } # Build custom embed embed = get_team_embed(f'{player["name"]} Career Stats') embed.color = int('0xa6ce39', 16) player_photo = await get_player_headshot(b['name']) if player_photo: embed.set_thumbnail(url=player_photo) player_pages = f'[SBa]({get_player_url(player)}) / ' \ f'[BBRef]({get_player_url(player, "bbref")})' embed.add_field(name='Player Page', value=player_pages) batting_string = None pitching_string = None if b: 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 HR RBI SB\n' \ f'{ab: ^4} {run: ^3} {hit: ^3} {hr: >3} {rbi: >3} ' \ f'{sb: >3}\n```' if p: 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: ^4} {whip: >4}\n```' if batting_string and pitching_string: if b['ab'] > p['ip']: embed.add_field(name='Batting Stats', value=batting_string, inline=False) else: embed.add_field(name='Pitching Stats', value=pitching_string, inline=False) elif batting_string: embed.add_field(name='Batting Stats', value=batting_string, inline=False) elif pitching_string: embed.add_field(name='Pitching Stats', value=pitching_string, inline=False) await ctx.send(content=None, embed=embed) @commands.command(name='schedule', help='This week and next') async def schedule_command(self, ctx, *week: int): current = await get_current() if week: schedule_week = week[0] elif current['week'] < 1: schedule_week = 1 else: schedule_week = current['week'] this_week_raw = await get_schedule( current['season'], week_start=schedule_week, week_end=schedule_week ) next_week_raw = await get_schedule( current['season'], week_start=schedule_week + 1, week_end=schedule_week + 1 ) results_this_week = await get_results( current['season'], week=schedule_week ) this_week = dict(sorted(this_week_raw.items(), key=lambda item: item[1]["id"])) next_week = dict(sorted(next_week_raw.items(), key=lambda item: item[1]["id"])) game_count = 0 for x in this_week: game_count += this_week[x]['gamecount'] embed = get_team_embed(f'Season {current["season"]} | Week {schedule_week} | ' f'{len(results_this_week)}/{game_count} games played') embed.add_field(name='Full Schedule', value=SBA_SCHEDULE_URL, inline=False) string_this_week_0 = '' string_this_week_1 = '' count = 0 for x in this_week: away_wins = 0 away_losses = 0 weekly_results = await get_results(current['season'], week=schedule_week, away_abbrev=this_week[x]['awayteam']['abbrev']) for y in weekly_results: if weekly_results[y]['awayteam'] == this_week[x]['awayteam'] and \ weekly_results[y]['hometeam'] == this_week[x]['hometeam']: if weekly_results[y]['awayscore'] > weekly_results[y]['homescore']: away_wins += 1 else: away_losses += 1 this_line = f'`({away_wins}) {this_week[x]["awayteam"]["abbrev"]: >4}` ' \ f'{await team_emoji(ctx, this_week[x]["awayteam"])} @ ' \ f'{await team_emoji(ctx, this_week[x]["hometeam"])} ' \ f'`{this_week[x]["hometeam"]["abbrev"]: <4} ({away_losses})`\n' if count > 8: string_this_week_1 += this_line else: string_this_week_0 += this_line count += 1 string_next_week_0 = '' string_next_week_1 = '' count = 0 for x in next_week: this_line = f'`{next_week[x]["awayteam"]["abbrev"]: >4}` ' \ f'{await team_emoji(ctx, next_week[x]["awayteam"])} @ ' \ f'{await team_emoji(ctx, next_week[x]["hometeam"])} ' \ f'`{next_week[x]["hometeam"]["abbrev"]: <4}`\n' if count > 8: string_next_week_1 += this_line else: string_next_week_0 += this_line count += 1 if len(string_this_week_0) > 0: embed.add_field( name=f'**Week {schedule_week} Games:**', value=string_this_week_0, inline=False ) await ctx.send(content=None, embed=embed) if len(string_this_week_1) > 0: if len(embed.fields) > 1: embed.remove_field(0) embed.set_field_at( index=0, name=f'**Week {schedule_week} Part 2:**', value=string_this_week_1, inline=False ) await ctx.send(content=None, embed=embed) if len(string_next_week_0) > 0: if len(embed.fields) > 1: embed.remove_field(0) embed.set_field_at( index=0, name=f'**Week {schedule_week + 1} Games:**', value=string_next_week_0, inline=False ) embed.title = f'Season {current["season"]} | Week {schedule_week + 1}' await ctx.send(content=None, embed=embed) if len(string_next_week_1) > 0: if len(embed.fields) > 1: embed.remove_field(0) embed.set_field_at( index=0, name=f'**Week {schedule_week + 1} Part 2:**', value=string_next_week_1, inline=False ) await ctx.send(content=None, embed=embed) @commands.command(name='weather', help='Roll ballpark weather') async def weather_command(self, ctx, *team_abbrev: str): current = await get_current() if team_abbrev: team = await get_one_team(team_abbrev[0]) else: team = await get_team_by_owner(current['season'], ctx.author.id) d_twenty = random.randint(1, 20) embed = get_team_embed('Weather Chart', team, thumbnail=False) embed.set_image(url=team['stadium']) embed.add_field(name=f'Weather roll for {ctx.author.name}', value=f'```md\n# {d_twenty}\nDetails:[1d20 ({d_twenty})]\n```') await ctx.send(content=None, embed=embed) @commands.command(name='standings', help='Current standings') async def standings_command(self, ctx): current = await get_current() div_one = await get_standings(current['season'], league_abbrev='al', division_abbrev='e') div_two = await get_standings(current['season'], league_abbrev='al', division_abbrev='w') div_three = await get_standings(current['season'], league_abbrev='nl', division_abbrev='e') div_four = await get_standings(current['season'], league_abbrev='nl', division_abbrev='w') div_one_standings = f'```\nTeam W-L PCT GB E# RD\n' for team in div_one: div_one_standings += self.team_stan_line(div_one[team]) div_one_standings += f'\n```' div_two_standings = f'```\nTeam W-L PCT GB E# RD\n' for team in div_two: div_two_standings += self.team_stan_line(div_two[team]) div_two_standings += f'\n```' div_three_standings = f'```\nTeam W-L PCT GB E# RD\n' for team in div_three: div_three_standings += self.team_stan_line(div_three[team]) div_three_standings += f'\n```' div_four_standings = f'```\nTeam W-L PCT GB E# RD\n' for team in div_four: div_four_standings += self.team_stan_line(div_four[team]) div_four_standings += f'\n```' progress = await self.game_progress(current) embed = discord.Embed(title=f'Season {current["season"]} | Week {current["week"]} | ' f'{progress["games_played"]}/{progress["game_count"]} games played', color=0xB70000) embed.add_field(name=f'**Full Standings**', value=SBA_STANDINGS_URL, inline=False) embed.add_field(name=f'**AL East**', value=div_one_standings, inline=False) embed.add_field(name=f'**AL West**', value=div_two_standings, inline=False) embed.add_field(name=f'**NL East**', value=div_three_standings, inline=False) embed.add_field(name=f'**NL West**', value=div_four_standings, inline=False) embed.set_footer(text='Run !wildcard to see wildcard standings') await ctx.send(content=None, embed=embed) @commands.command(name='wildcard', aliases=['wc'], help='Current wildcard') async def wildcard_command(self, ctx): current = await get_current() al_teams = await get_standings(current['season'], league_abbrev='al') nl_teams = await get_standings(current['season'], league_abbrev='nl') al_wildcard = f'```\nTeam W-L PCT GB E# RD\n' for team in al_teams: al_wildcard += self.team_stan_line(al_teams[team], s_type='wc') al_wildcard += '```' nl_wildcard = f'```\nTeam W-L PCT GB E# RD\n' for team in nl_teams: nl_wildcard += self.team_stan_line(nl_teams[team], s_type='wc') nl_wildcard += '```' progress = await self.game_progress(current) embed = discord.Embed(title=f'Season {current["season"]} | Week {current["week"]} | ' f'{progress["games_played"]}/{progress["game_count"]} games played', color=0xB70000) embed.add_field(name=f'**Full Standings**', value=SBA_STANDINGS_URL, inline=False) embed.add_field(name=f'**AL Wildcard**', value=al_wildcard, inline=False) embed.add_field(name=f'**NL Wildcard**', value=nl_wildcard, inline=False) embed.set_footer(text='Run !standings to see divisional standings') await ctx.send(content=None, embed=embed) # @commands.command(name='setinjury', aliases=['clearinjury'], help='!SetInjury or !ClearInjury') # @commands.has_any_role(SBA_PLAYERS_ROLE_NAME) # async def set_injury_command(self, ctx, *, player_name): # await ctx.send('This command has been deprecated. Please use `/setinjury` or `/clearinjury`') # return # # current = await get_current() # # player = await get_one_player(player_name) # # # Check if player is on owner's team # team = await get_team_by_owner(current['season'], ctx.author.id) # if not player['team'] == team and not player['team']['abbrev'][:len(team['abbrev'])] == team['abbrev']: # await ctx.send(f'Is this some kind of tom foolery? {player["name"]} is on {player["team"]["abbrev"]} aka ' # f'not your team. I\'m watching you.') # return # # embed = get_team_embed(f'Injury Update', team=team) # if player['il_return']: # # Confirm injury is over # old_injury = player['il_return'] # prompt = f'{player["name"]}\'s return was set for {player["il_return"]}. Is he eligible to play again?' # this_q = Question(self.bot, ctx.channel, prompt, 'yesno', 60.0) # resp = await this_q.ask([ctx.author]) # if not resp: # await ctx.send('Okay, let me know when it\'s over.') # return # else: # player['il_return'] = None # if await patch_player(player['id'], il_return=False): # embed.add_field( # name=f'{player["name"]}', # value=f'{team["sname"]} {player["pos_1"]} {player["name"]}\'s injury ({old_injury}) has ended' # ) # # await log_channel.send( # # f'{player["team"]["sname"]} {player["pos_1"]} {player["name"]}\'s IL stint is over.' # # ) # else: # # Get injury end date # prompt = f'When is {player["name"]} eligible to play again? (eg: w17g2)' # this_q = Question(self.bot, ctx.channel, prompt, 'text', 60.0) # resp = await this_q.ask([ctx.author]) # injury_pattern = 'wk[0-9]+g[1-7]|w[0-9]+g[1-7]' # # if not resp: # await ctx.send('Tell you hwat. You recount it. Math is hard. Then you can get back to me.') # return # elif not re.search(injury_pattern, resp.lower()): # await ctx.send('I, uh...I was expecting something shorter like this: w12g4. Try again maybe?') # return # else: # date_list = re.split('[a-z]+', resp.lower()) # return_date = f'w{date_list[1]:0>2}g{date_list[2]}' # player['il_return'] = return_date # if await patch_player(player['id'], il_return=return_date): # embed.add_field( # name=f'{player["name"]}', # value=f'{team["sname"]} {player["pos_1"]} {player["name"]} is injured until {return_date}' # ) # # await log_channel.send( # # f'{player["team"]["sname"]} {player["pos_1"]} {player["name"]} can return {player["il_return"]}' # # ) # # await ctx.send(random_salute_gif()) # await send_to_channel(self.bot, 'sba-network-news', content=None, embed=embed) # await self.update_injuries(ctx) @app_commands.command(name='setinjury', description='Set the return date for injured player') @app_commands.guilds(discord.Object(id=os.environ.get('GUILD_ID'))) @app_commands.describe( player_name='Name of injured player', this_week='The current SBa week', this_game='The game number in which the player got injured', inj_games='The number of games the player will miss' ) @app_commands.checks.has_any_role(SBA_PLAYERS_ROLE_NAME) async def set_injury_slash( self, interaction: discord.Interaction, player_name: str, this_week: int, this_game: int, inj_games: int): current = await get_current() player = await get_one_player(player_name) # Check if player is on owner's team team = await get_team_by_owner(current['season'], interaction.user.id) if not player['team'] == team and not player['team']['abbrev'][:len(team['abbrev'])] == team['abbrev']: await interaction.response.send_message( f'Is this some kind of tom foolery? {player["name"]} is on {player["team"]["abbrev"]} aka ' f'not your team. I\'m watching you.' ) return out_weeks = math.floor(inj_games / 4) out_games = inj_games % 4 return_week = this_week + out_weeks return_game = this_game + 1 + out_games if this_game + 1 + out_games > 4: return_week += 1 return_game -= 4 return_date = f'w{return_week:>02}g{return_game:>02}' if await patch_player(player['id'], il_return=return_date): await patch_current(injury_count=current['injury_count'] + 1) embed = get_team_embed(f'Injury Update', team=team) embed.add_field( name=f'{player["name"]}', value=f'{team["sname"]} {player["pos_1"]} {player["name"]} is injured until {return_date}' ) await log_injury( current, {'player': player, 'type': 'new', 'current_game': this_game, 'injury_length': inj_games} ) await interaction.response.send_message(random_salute_gif()) await send_to_channel(self.bot, 'sba-network-news', content=None, embed=embed) await self.update_injuries(interaction) else: await interaction.response.send_message('Well that didn\'t work.') @app_commands.command(name='clearinjury', description='Clear the injury for a player') @app_commands.describe(player_name='Name of injured player') @app_commands.checks.has_any_role(SBA_PLAYERS_ROLE_NAME) async def clear_injury_slash(self, interaction: discord.Interaction, player_name: str): current = await get_current() player = await get_one_player(player_name) if not player['il_return']: await interaction.response.send_message('Huh? He isn\'t injured, numb nuts.') return team = await get_team_by_owner(current['season'], interaction.user.id) if not player['team'] == team and not player['team']['abbrev'][:len(team['abbrev'])] == team['abbrev']: await interaction.response.send_message( f'Is this some kind of tom foolery? {player["name"]} is on {player["team"]["abbrev"]} aka ' f'not your team. I\'m watching you.' ) return old_injury = player['il_return'] await interaction.response.send_message(f'{player["name"]}\'s return was set for {player["il_return"]}.') view = Confirm(responders=[interaction.user]) question = await interaction.channel.send('Is he eligible to play again?', view=view) await view.wait() if view.value: player['il_return'] = None if await patch_player(player['id'], il_return=False): await patch_current(injury_count=current['injury_count'] + 1) embed = get_team_embed(f'Injury Update', team=team) embed.add_field( name=f'{player["name"]}', value=f'{team["sname"]} {player["pos_1"]} {player["name"]}\'s injury ({old_injury}) has ended' ) await log_injury( current, {'player': player, 'type': 'clear', 'current_game': None, 'injury_length': None} ) await question.edit(content=random_conf_gif(), view=None) await send_to_channel(self.bot, 'sba-network-news', content=None, embed=embed) await self.update_injuries(interaction) else: await interaction.response.message_update('Well that didn\'t work.') else: await question.edit(content='You keep thinking on it.', view=None) # @commands.command(name='result', help='Log result') # @commands.has_any_role(SBA_PLAYERS_ROLE_NAME) # async def result_command( # self, ctx, away_abbrev: str, away_score: int, home_abbrev: str, home_score: int, *week: int): # # current = await get_current() # # away_team = await get_one_team(away_abbrev) # # home_team = await get_one_team(home_abbrev) # # this_week = week[0] if week else current['week'] # # # # this_matchup = await get_schedule(current['season'], week_start=this_week, week_end=this_week, # # away_abbrev=away_team["abbrev"], home_abbrev=home_team["abbrev"]) # # these_results = await get_results(current['season'], week=this_week, away_abbrev=away_team["abbrev"], # # home_abbrev=home_team["abbrev"]) # # # # # Check if scores match a weekly matchup # # game_count = 0 # # legal = False # # for x in this_matchup: # # if this_matchup[x]['awayteam'] == away_team and this_matchup[x]['hometeam'] == home_team: # # legal = True # # game_count = this_matchup[x]['gamecount'] # # if not legal: # # raise ValueError(f'I do not see a matchup between {away_team["abbrev"]} and {home_team["abbrev"]} ' # # f'in week {this_week}') # # # # # Check if author is gm of these teams or the bot owner # # if ctx.author.id not in [away_team['gmid'], away_team['gmid2'], home_team['gmid'], home_team['gmid2']] \ # # and ctx.author.id != self.bot.owner_id: # # await ctx.message.add_reaction('❌') # # raise PermissionError('Only GMs of these teams can enter results') # # # # if len(these_results) >= game_count: # # raise ValueError('It looks like that series is complete') # # # # prompt = f'Should I log {away_team["abbrev"]} {await team_emoji(ctx, away_team)} {away_score} @ ' \ # # f'{home_score} {await team_emoji(ctx, home_team)} {home_team["abbrev"]} ' \ # # f'as w{this_week}g{len(these_results) + 1}?' # # this_q = Question(self.bot, ctx.channel, prompt, 'yesno', 45) # # resp = await this_q.ask([ctx.author]) # # # # if not resp: # # await ctx.send('No worries, I\'ll be here when you\'re ready.') # # return # # else: # # result = { # # 'week': this_week, # # 'game': len(these_results) + 1, # # 'away_team_id': away_team['id'], # # 'home_team_id': home_team['id'], # # 'away_score': away_score, # # 'home_score': home_score, # # 'season': current['season'] # # } # # if await post_result(result): # # await ctx.message.add_reaction('✅') # # await ctx.send(random_conf_gif()) # # update = await ctx.send('I\'m tallying standings now...') # # if await post_standings_recalc(current['season']): # # await update.delete() # await ctx.send(f'You no longer have to submit scores manually. They will be added when you run `/sba-submit`') # @commands.command(name='drive', help='Season 5 Drive') # async def drive_command(self, ctx): # await ctx.send('Here is a link to the Season 5 drive:\n' # 'https://drive.google.com/drive/folders/1W8B54gZsDXXT3coKVtnGYNiYnUAPcwNB?usp=sharing') # @commands.command(name='rules', aliases=['rulesref', 'rulesreference', 'reference'], help='Rules reference') # async def rules_command(self, ctx): # await ctx.send('Here is the online rules reference: \n\n' # 'Here is a link to the google doc:\n' # 'https://docs.google.com/document/d/1yGZcHy9zN2MUi4hnce12dAzlFpIApbn7zR24vCkPl1o') @commands.command(name='links', aliases=['scorecards', 'scorecard', 'link', 'resources', 'resource'], help='Links for league resources') async def scorecard_command(self, ctx): await ctx.send( '***S C O R E C A R D S***\n' '**OG Card**:\n\n' '**S6 PCD**:\n\n' '**Foxx\'s**:\n\n' '**Josef\'s**:\n\n\n' '***R E F E R E N C E S***\n' '**Rules Reference**:\n\n' '**League Guidelines**:\n\n' '**Scouting Reference**:\n' ) @commands.command(name='rest', help='Pitcher rest charts', hidden=True) async def rest_command(self, ctx): # sp_rest_url = 'https://lh3.googleusercontent.com/pw/ACtC-3eeRv52FZIUZNNafBBpwxJIx_OViLYHbsyi129GkJkIiv7r-X3O' \ # 'In9_mfkr9GVl2NbLhCJ9j1IQD5DX75bLwX0gVAFExkGNolnngKck9yx6g-qjQ6QoXkc2t821UwxGoRNbZadxfd3wUn32a' \ # 'zdQnJxnZw=w419-h703-no?authuser=0' # rp_rest_url = 'https://lh3.googleusercontent.com/pw/ACtC-3eU_nNLYv2KLJTCom9BUSkjY-kD-VBumaiPYQxzfDB23yvkozLc' \ # 'Qt9ai-xIwXe7CsGJ61qKgv6s6-lJp3_LRImwDFfP2VzUyPDFjE3P_CiuL6FsZCrzIBylQdLBXtxEsVmnGeSLv1WtJ--Wf' \ # '3KzZVoOkQ=w525-h453-no?authuser=0' # # sp_embed = discord.Embed(title='SP Rest Chart') # sp_embed.set_image(url=sp_rest_url) # await ctx.send(content=None, embed=sp_embed) # # rp_embed = discord.Embed(title='RP Rest Chart') # rp_embed.set_image(url=rp_rest_url) # await ctx.send(content=None, embed=rp_embed) # await ctx.send('For full rules, see ') await ctx.send('This command has been deprecated - please run `/charts rest`') @app_commands.command(name='sba-submit', description='Submit scorecard and game result') @app_commands.checks.has_any_role(SBA_PLAYERS_ROLE_NAME) async def submit_slash(self, interaction: discord.Interaction, sheet_url: str): current = await get_current() # Go get scorecard await interaction.response.send_message(content='I\'ll go grab that card now...') logging.info(f'Checking scorecard {sheet_url}') # Try to get card try: sheets = pygsheets.authorize(service_file='storage/major-domo-service-creds.json') scorecard = sheets.open_by_url(sheet_url).worksheet_by_title('Results') except Exception as e: logging.error(f'Failed to access scorecard {sheet_url}: {e}') await interaction.edit_original_response(content='Is that sheet public? I can\'t access it.') return # Get outline data from the sheet try: away_bats = scorecard.get_values('A3', 'AK19') home_bats = scorecard.get_values('A33', 'AK49') away_arms = scorecard.get_values('A22', 'V30') home_arms = scorecard.get_values('A52', 'V59') away_team = await get_one_team(away_arms[0][1]) home_team = await get_one_team(home_arms[0][1]) week_num = away_bats[0][35] game_num = home_bats[0][36] except Exception as e: logging.error(f'Failed to read scorecard {sheet_url}: {e}') await interaction.edit_original_response(content=f'Oof, I got you an error:\n\n{e}.') return # Confirm teams and matchup this_matchup = await get_schedule( current['season'], away_abbrev=away_team['abbrev'], home_abbrev=home_team['abbrev'], week_start=week_num, week_end=week_num ) if len(this_matchup) != 1: await interaction.edit_original_response( content=f'Hmm...it doesn\'t look like {away_team["abbrev"]} played {home_team["abbrev"]} in ' f'week {week_num}.' ) return # Confirm stats for game don't already exist old_home_bat = await get_battingstat( season=current['season'], team_abbrev=home_team['abbrev'], week_start=week_num, week_end=week_num, game_num=game_num) old_away_bat = await get_battingstat( season=current['season'], team_abbrev=away_team['abbrev'], week_start=week_num, week_end=week_num, game_num=game_num) old_home_arm = await get_pitchingstat( season=current['season'], team_abbrev=home_team['abbrev'], week_start=week_num, week_end=week_num, game_num=game_num) old_away_arm = await get_pitchingstat( season=current['season'], team_abbrev=away_team['abbrev'], week_start=week_num, week_end=week_num, game_num=game_num) # Confirm submitting GM if await get_team_by_owner(current['season'], interaction.user.id) not in [home_team, away_team] and \ interaction.user.id != self.bot.owner_id: await interaction.edit_original_response( content=f'{await get_emoji(interaction, "squint")} Only a GM of the two teams can submit scorecards.' ) return if len(old_home_bat) + len(old_away_bat) + len(old_home_arm) + len(old_away_arm) > 0: view = Confirm(responders=[interaction.user]) question = await interaction.channel.send( f'I already see stats for {away_team["abbrev"]} @ {home_team["abbrev"]} week {week_num} game ' f'{game_num}. Would you like me to remove those and update with this card?', view=view ) await view.wait() if view.value: logging.info(f'sba-submit - view.value') this_game = { 'season': current['season'], 'week': week_num, 'game_num': game_num, 'away_team_id': away_team['id'], 'home_team_id': home_team['id'] } await question.edit( content='What a pain in my balls. Let\'s start by deleting the batting stats...', view=None ) if await delete_battingstats(this_game): await question.edit(content='Batting stats are gone - now the pitching stats...') if await delete_pitchingstats(this_game): await question.edit( content='Pitching stats are gone - now to recalculate everybody\'s season batting lines...' ) if await recalc_batting_seasons(current['season'], away_team['id']): if await recalc_batting_seasons(current['season'], home_team['id']): await question.edit( content='Batting lines are done - now to recalculate pitching lines...' ) if await recalc_pitching_seasons(current['season'], away_team['id']): if await recalc_pitching_seasons(current['season'], home_team['id']): await question.edit( content='Pitching lines are done - now to recalculate fielding lines...' ) if await recalc_fielding_seasons(current['season'], away_team['id']): if await recalc_fielding_seasons(current['season'], home_team['id']): await question.edit( content=f'All done. Don\'t suck next time ' f'{await get_emoji(interaction.guild, "lakemonsters")}' ) week_games = await get_results( current['season'], away_abbrev=away_team['abbrev'], home_abbrev=home_team['abbrev'], week=week_num ) this_game = None for x in week_games: if week_games[x]['game'] == game_num: this_game = week_games[x] break if this_game: await delete_result(this_game['id']) else: logging.info(f'sba-submit - view.value "else"') await interaction.channel.send('Alright, we\'ll call it a day here.') return logging.info(f'sba-submit - reading scorecard') # Read scorecard errors = [] b_counts = {'sbc': 0, 'csc': 0, 'sb': 0, 'cs': 0, 'so': 0, 'bb': 0, 'run': 0, 'rbi': 0, 'xba': 0, 'xbt': 0, 'raa': 0, 'rto': 0} p_counts = {'gs': 0, 'win': 0, 'loss': 0, 'so': 0, 'bb': 0, 'run': 0, 'erun': 0, 'ir': 0, 'irs': 0} positions = ['C', '1B', '2B', '3B', 'SS', 'LF', 'CF', 'RF', 'DH', 'PH', 'PR', 'P'] pit_nums = [f'{x}' for x in range(20)] bat_stats = ['player', 'team', 'pos', 'pa', 'ab', 'run', 'hit', 'rbi', 'double', 'triple', 'hr', 'bb', 'so', 'hbp', 'sac', 'ibb', 'gidp', 'sb', 'cs', 'bphr', 'bpfo', 'bp1b', 'bplo', 'xba', 'xbt', 'xch', 'xhit', 'error', 'pb', 'sbc', 'csc', 'roba', 'robs', 'raa', 'rto', 'week', 'game'] pit_stats = ['player', 'team', 'ip', 'hit', 'run', 'erun', 'so', 'bb', 'hbp', 'wp', 'balk', 'hr', 'ir', 'irs', 'gs', 'win', 'loss', 'hold', 'sv', 'bsv', 'week', 'game'] new_bat_stats = [] new_pit_stats = [] final_box_away = {'r': 0, 'h': 0, 'e': 0, 'ip': 0} final_box_home = {'r': 0, 'h': 0, 'e': 0, 'ip': 0} final_wp = None final_lp = None final_holds = [] final_sv = None final_bsv = [] final_doubles = [] final_triples = [] final_homeruns = [] final_sbs = [] final_cscs = [] # Read batting stats for group in [away_bats, home_bats]: for line in group: if line[0]: # Dictionary to hold data to be passed to db for BatStat model this_batter = {'season': current['season']} # Keeping count so we can add stat name and data from sheet into this_batter dict for count in range(len(bat_stats)): if line[count] != '' and line[count] != '#REF' and line[count] != 0: this_batter[bat_stats[count]] = line[count] # Add this_batter to collection new_bat_stats try: this_batter['player_id'] = self.player_list[line[0].lower()] this_batter['team_id'] = away_team['id'] if line[1].lower() == away_team['abbrev'].lower() \ else home_team['id'] # Check for pitcher int in position if this_batter['pos'] in pit_nums: this_batter['pos'] = 'P' this_bat_stat = BatStat.parse_obj(this_batter) new_bat_stats.append(this_bat_stat.dict()) # Get stats for news-ticker if this_batter['team_id'] == away_team['id']: final_box_away['r'] += this_bat_stat.run final_box_away['h'] += this_bat_stat.hit final_box_away['e'] += this_bat_stat.error else: final_box_home['r'] += this_bat_stat.run final_box_home['h'] += this_bat_stat.hit final_box_home['e'] += this_bat_stat.error if this_bat_stat.double: final_doubles.append((this_batter['player_id'], this_bat_stat.double)) if this_bat_stat.triple: final_triples.append((this_batter['player_id'], this_bat_stat.triple)) if this_bat_stat.hr: final_homeruns.append((this_batter['player_id'], this_bat_stat.hr)) if this_bat_stat.sb: final_sbs.append((this_batter['player_id'], this_bat_stat.sb)) if this_bat_stat.csc: final_cscs.append((this_batter['player_id'], this_bat_stat.csc)) except Exception as e: errors.append(f'{line[0]}: {e}') # Read pitching stats for group in [away_arms, home_arms]: for line in group: if line[0]: # Dictionary to hold data for PitStat model this_pitcher = {'season': current['season']} # Keeping count so we can add stat name and data from sheet into this_pitcher dict for count in range(len(pit_stats)): if line[count] != '' and line[count] != '#REF' and line[count] != 0: this_pitcher[pit_stats[count]] = line[count] # Add this_pitcher to collection new_pit_stats try: this_pitcher['player_id'] = self.player_list[line[0].lower()] this_pitcher['team_id'] = away_team['id'] if line[1].lower() == away_team['abbrev'].lower() \ else home_team['id'] this_pit_stat = PitStat.parse_obj(this_pitcher) # Update IP to an even third first_digit = f'{this_pit_stat.ip % 1}'[2] if first_digit == '0': this_pit_stat.ip = math.floor(this_pit_stat.ip) elif first_digit in ['1', '3']: this_pit_stat.ip = math.floor(this_pit_stat.ip) + (1/3) else: this_pit_stat.ip = math.floor(this_pit_stat.ip) + (2/3) new_pit_stats.append(this_pit_stat.dict()) # Get stats for news-ticker if this_pit_stat.win: final_wp = this_pit_stat.player_id if this_pit_stat.loss: final_lp = this_pit_stat.player_id if this_pit_stat.sv: final_sv = this_pit_stat.player_id if this_pit_stat.bsv: final_bsv.append(this_pit_stat.player_id) if this_pit_stat.hold: final_holds.append(this_pit_stat.player_id) if this_pitcher['team_id'] == away_team['id']: final_box_away['ip'] += this_pit_stat.ip else: final_box_home['ip'] += this_pit_stat.ip except Exception as e: errors.append(f'{line[0]}: {e}') # Error checks await interaction.edit_original_response( content='Just finished reading the scorecard. Now to look for all of your mistakes...' ) for line in new_bat_stats: b_counts['sbc'] += line['sbc'] b_counts['csc'] += line['csc'] b_counts['sb'] += line['sb'] b_counts['cs'] += line['cs'] b_counts['so'] += line['so'] b_counts['bb'] += line['bb'] + line['ibb'] b_counts['run'] += line['run'] b_counts['rbi'] += line['rbi'] b_counts['xba'] += line['xba'] b_counts['xbt'] += line['xbt'] b_counts['raa'] += line['raa'] b_counts['rto'] += line['rto'] if line['pos'] not in positions: errors.append(f'{line["pos"]} not a valid position') for line in new_pit_stats: logging.info(f'line: {line}') p_counts['gs'] += line['gs'] p_counts['win'] += line['win'] p_counts['loss'] += line['loss'] p_counts['bb'] += line['bb'] p_counts['so'] += line['so'] p_counts['run'] += line['run'] p_counts['erun'] += line['erun'] p_counts['ir'] += line['ir'] p_counts['irs'] += line['irs'] if b_counts['sbc'] > b_counts['sb'] + b_counts['cs']: errors.append(f'There are {b_counts["sbc"]} stolen base attempts (SBa), but {b_counts["sb"]} SB and ' f'{b_counts["cs"]} CS.') if b_counts['csc'] > b_counts['cs']: errors.append(f'There are {b_counts["sbc"]} catcher caught stealings (CSc), but ' f'{b_counts["cs"]} baserunner CS.') if b_counts['so'] != p_counts['so']: errors.append(f'There are {b_counts["so"]} batter strikeouts, but {p_counts["so"]} pitcher strikeouts.') if b_counts['bb'] != p_counts['bb']: errors.append(f'There are {b_counts["bb"]} batter walks, but {p_counts["bb"]} pitcher.') if b_counts['run'] != p_counts['run']: errors.append(f'There are {b_counts["run"]} batter runs, but {p_counts["run"]} pitcher runs.') if b_counts['rbi'] > b_counts['run']: errors.append(f'There are {b_counts["rbi"]} runs batted in, but {b_counts["run"]} runs scored.') if b_counts['rto'] > b_counts['raa']: errors.append(f'There are {b_counts["rto"]} runners thrown out, but {b_counts["raa"]} runner ' f'advance attempts.') if b_counts['xbt'] > b_counts['xba']: errors.append(f'There are {b_counts["xbt"]} extra bases taken, but {b_counts["xba"]} extra ' f'base attempts.') if p_counts['erun'] > p_counts['run']: errors.append(f'There are {p_counts["erun"]} earned runs and {p_counts["run"]} total runs. ') if p_counts['gs'] != 2: errors.append(f'There should be 2 GS, but I see {p_counts["gs"]} of them.') if p_counts['win'] != 1: errors.append(f'There should be 1 W, but I see {p_counts["win"]} of them.') if p_counts['loss'] != 1: errors.append(f'There should be 1 L, but I see {p_counts["loss"]} of them.') if p_counts['irs'] > p_counts['ir']: errors.append(f'There are {p_counts["irs"]} inherited runners scored and {p_counts["ir"]} ' f'inherited runners.') # Post errors, if any, or post stats to db if len(errors) > 0: error_message = '\n- '.join(errors) await interaction.edit_original_response( content=f'The following errors were found in your **wk{week_num}g{game_num}** scorecard. ' f'Please resolve them and resubmit - thanks!\n\n- {error_message}' ) logging.error(f'Scorecard errors: {error_message}') return else: bat_conf = await post_battingstats(new_bat_stats) pit_conf = await post_pitchingstats(new_pit_stats) if bat_conf and pit_conf: await interaction.edit_original_response( content=f'You did it! I just logged the stats for **wk{week_num}g{game_num}**' ) # Update last games for pitchers for x in new_pit_stats: this_pitcher = await get_one_player(x["player_id"]) game_string = f'{float(x["ip"]):.2}IP w{x["week"]}g{x["game"]}' await patch_player(this_pitcher['id'], last_game=game_string, last_game2=this_pitcher['last_game']) else: await interaction.edit_original_response( content='So the stats looked okay, but I had an accident when I tried to post them. They ' 'did not go through.' ) # Post scorecard to weekly archive card_url = f'<{SBA_BASE_URL}/scorecards/?season={current["season"]}&week={week_num}&game={game_num}' \ f'&away_abbrev={away_team["abbrev"]}&home_abbrev={home_team["abbrev"]}>' # try: # archive_channel = get_channel(interaction, name=f'week-{week_num}-archive') # logging.info(f'archive_channel: {archive_channel}') # if not archive_channel: # archive_channel = await create_channel( # interaction, # channel_name=f'week-{week_num}-archive', # category_name=f'Season {current["season"]} Archives', # read_send_roles=[get_role(interaction, 'Gameplay Bots')] # ) # # await archive_channel.send( # f'Game {game_num}: **{away_team["sname"]}** {await team_emoji(interaction, away_team)} ' # f'{final_box_away["r"]} @ {final_box_home["r"]} ' # f'{await team_emoji(interaction, home_team)} **{home_team["sname"]}**\n{card_url}') # except Exception as e: # await interaction.edit_original_response( # content='Ope. I wasn\'t able to post this to the archive channel.' # ) # Post box score to news-ticker extras = '' if final_box_home['ip'] > 9: extras = f' F/{math.floor(final_box_home["ip"])}' embed = get_team_embed( f'{away_team["sname"]} {final_box_away["r"]} @ ' f'{final_box_home["r"]} {home_team["sname"]}{extras}', team=away_team if final_box_away['r'] > final_box_home['r'] else home_team ) embed.description = f'Week {week_num} | Game {game_num}' embed.add_field( name='Box Score', value=f'```\n' f'Team | R | H | E |\n' f'{away_team["abbrev"]: <4} | {final_box_away["r"]: >2} | {final_box_away["h"]: >2} | ' f'{final_box_away["e"]: >2} |\n' f'{home_team["abbrev"]: <4} | {final_box_home["r"]: >2} | {final_box_home["h"]: >2} | ' f'{final_box_home["e"]: >2} |\n' f'```', inline=False ) wp = await get_one_player(final_wp) lp = await get_one_player(final_lp) if final_sv: sv = await get_one_player(final_sv) else: sv = None holds = [] bsvs = [] for x in final_holds: holds.append(await get_one_player(x)) for x in final_bsv: bsvs.append(await get_one_player(x)) pitching_string = f'WP: {wp["name"]}\n' \ f'LP: {lp["name"]}\n' \ f'{"HD: " if len(holds) > 0 else ""}' hold_string = '' count = 1 for x in holds: hold_string += f'{x["name"]}' if count < len(holds): hold_string += ', ' elif len(holds) > 0: hold_string += '\n' count += 1 pitching_string += hold_string if sv: pitching_string += f'SV: {sv["name"]}' embed.add_field(name='Pitching', value=pitching_string, inline=False) batting_string = '' count = 1 if len(final_doubles) > 0: batting_string += '2B: ' for x in final_doubles: player = await get_one_player(x[0]) batting_string += f'{player["name"]}' if x[1] > 1: batting_string += f' {x[1]}' if count < len(final_doubles): batting_string += ', ' else: batting_string += '\n' count += 1 count = 1 if len(final_triples) > 0: batting_string += '3B: ' for x in final_triples: player = await get_one_player(x[0]) batting_string += f'{player["name"]}' if x[1] > 1: batting_string += f' {x[1]}' if count < len(final_triples): batting_string += ', ' else: batting_string += '\n' count += 1 count = 1 if len(final_homeruns) > 0: batting_string += 'HR: ' for x in final_homeruns: player = await get_one_player(x[0]) batting_string += f'{player["name"]}' if x[1] > 1: batting_string += f' {x[1]}' if count < len(final_homeruns): batting_string += ', ' else: batting_string += '\n' count += 1 if len(batting_string) > 0: embed.add_field(name='Batting', value=batting_string, inline=False) baserunning_string = '' count = 1 if len(final_sbs) > 0: baserunning_string += 'SB: ' for x in final_sbs: player = await get_one_player(x[0]) baserunning_string += f'{player["name"]}' if x[1] > 1: baserunning_string += f' {x[1]}' if count < len(final_sbs): baserunning_string += ', ' else: baserunning_string += '\n' count += 1 count = 1 if len(final_cscs) > 0: baserunning_string += 'CSc: ' for x in final_cscs: player = await get_one_player(x[0]) baserunning_string += f'{player["name"]}' if x[1] > 1: baserunning_string += f' {x[1]}' if count < len(final_cscs): baserunning_string += ', ' else: baserunning_string += '\n' count += 1 if len(baserunning_string) > 0: embed.add_field(name='Baserunning', value=baserunning_string, inline=False) embed.add_field( name='Scorecard', value=f'[Website]({card_url}) / [Sheets]({sheet_url})' ) embed.set_footer(text='Please share the highlights!') await send_to_channel( self.bot, 'sba-network-news', content=None, embed=embed ) result = { 'week': week_num, 'game': game_num, 'away_team_id': away_team['id'], 'home_team_id': home_team['id'], 'away_score': final_box_away["r"], 'home_score': final_box_home["r"], 'season': current['season'], 'scorecard_url': sheet_url } if await post_result(result): update = await interaction.channel.send('I\'m tallying standings now...') if await post_standings_recalc(current['season']): await update.delete() # @commands.command(name='submit', help='Submit scorecard') # @commands.has_any_role(SBA_PLAYERS_ROLE_NAME) # async def submit_command(self, ctx, sheet_url): # # current = await get_current() # # # # # Ask for confirmation to pull card # # prompt = 'Has your opponent double-checked this card for accuracy? They get pretty whiny when you miss ' \ # # 'a hold or an RBI. (Yes/No)' # # this_q = Question(bot=self.bot, channel=ctx.channel, prompt=prompt, qtype='yesno', timeout=30) # # async with ctx.typing(): # # if not os.environ.get("TESTING"): # # await asyncio.sleep(4) # # resp = await this_q.ask([ctx.author]) # # # # if not resp: # # await ctx.send('Not a problem at all. You folks think it over and come back to me when you\'re sure.') # # return # # else: # # await ctx.message.add_reaction('👀') # # await ctx.send('Hold my sheets, I\'m going in.') # # # # # Go get scorecard # # logging.info(f'Checking scorecard {sheet_url}') # # async with ctx.typing(): # # # Try to get card # # try: # # sheets = pygsheets.authorize(service_file='storage/major-domo-service-creds.json') # # scorecard = sheets.open_by_url(sheet_url).worksheet_by_title('Results') # # except Exception as e: # # logging.error(f'Failed to open scorecard {sheet_url} with this error: {e}') # # await ctx.message.add_reaction('❌') # # await ctx.send(f'{ctx.message.author.mention}, I can\'t access that sheet.') # # return # # # # # Get outline data from the sheet # # try: # # away_bats = scorecard.get_values('A3', 'AK19') # # home_bats = scorecard.get_values('A33', 'AK49') # # away_arms = scorecard.get_values('A22', 'V29') # # home_arms = scorecard.get_values('A52', 'V59') # # away_team = await get_one_team(away_arms[0][1]) # # home_team = await get_one_team(home_arms[0][1]) # # week_num = away_bats[0][35] # # game_num = home_bats[0][36] # # except Exception as e: # # logging.error(f'Failed to read scorecard {sheet_url} with this error: {e}') # # await ctx.message.add_reaction('❌') # # await ctx.send(f'Yikes. I ran into an error reading this card. This could be ugly:\n\n{e}') # # return # # # # # Confirm teams and matchup # # this_matchup = await get_schedule( # # current['season'], away_abbrev=away_team['abbrev'], home_abbrev=home_team['abbrev'], week_start=week_num, # # week_end=week_num # # ) # # if len(this_matchup) != 1: # # await ctx.send(f'Hmm...it doesn\'t look like {away_team["abbrev"]} played {home_team["abbrev"]} in ' # # f'week {week_num}.') # # return # # # # # Confirm stats for game don't already exist # # old_home_bat = await get_battingstat( # # season=current['season'], team_abbrev=home_team['abbrev'], week_start=week_num, # # week_end=week_num, game_num=game_num) # # old_away_bat = await get_battingstat( # # season=current['season'], team_abbrev=away_team['abbrev'], week_start=week_num, # # week_end=week_num, game_num=game_num) # # old_home_arm = await get_pitchingstat( # # season=current['season'], team_abbrev=home_team['abbrev'], week_start=week_num, # # week_end=week_num, game_num=game_num) # # old_away_arm = await get_pitchingstat( # # season=current['season'], team_abbrev=away_team['abbrev'], week_start=week_num, # # week_end=week_num, game_num=game_num) # # # # if len(old_home_bat) + len(old_away_bat) + len(old_home_arm) + len(old_away_arm) > 0: # # if len(old_home_bat) > 0: # # await ctx.send(f'I already see batting stats for the {home_team["sname"]} from w{week_num}g{game_num}') # # if len(old_away_bat) > 0: # # await ctx.send(f'I already see batting stats for the {away_team["sname"]} from w{week_num}g{game_num}') # # if len(old_home_arm) > 0: # # await ctx.send(f'I already see pitching stats for the {home_team["sname"]} from w{week_num}g{game_num}') # # if len(old_away_arm) > 0: # # await ctx.send(f'I already see pitching stats for the {away_team["sname"]} from w{week_num}g{game_num}') # # await ctx.send('Double check the week and game number and then get back to me.') # # return # # # # # Confirm submitting GM # # if await get_team_by_owner(current['season'], ctx.author.id) not in [home_team, away_team] and \ # # ctx.author.id != self.bot.owner_id: # # await ctx.send(f'{await get_emoji(ctx, "squint")} Only a GM of the two teams can submit scorecards.') # # return # # # # # Read scorecard # # errors = [] # # b_counts = {'sbc': 0, 'csc': 0, 'sb': 0, 'cs': 0, 'so': 0, 'bb': 0, 'run': 0, 'rbi': 0, 'xba': 0, 'xbt': 0, # # 'raa': 0, 'rto': 0} # # p_counts = {'gs': 0, 'win': 0, 'loss': 0, 'so': 0, 'bb': 0, 'run': 0, 'erun': 0, 'ir': 0, 'irs': 0} # # positions = ['C', '1B', '2B', '3B', 'SS', 'LF', 'CF', 'RF', 'DH', 'PH', 'PR', 'P'] # # pit_nums = [f'{x}' for x in range(20)] # # # # bat_stats = ['player', 'team', 'pos', 'pa', 'ab', 'run', 'hit', 'rbi', 'double', 'triple', 'hr', 'bb', 'so', # # 'hbp', 'sac', 'ibb', 'gidp', 'sb', 'cs', 'bphr', 'bpfo', 'bp1b', 'bplo', 'xba', 'xbt', 'xch', # # 'xhit', 'error', 'pb', 'sbc', 'csc', 'roba', 'robs', 'raa', 'rto', 'week', 'game'] # # pit_stats = ['player', 'team', 'ip', 'hit', 'run', 'erun', 'so', 'bb', 'hbp', 'wp', 'balk', 'hr', 'ir', 'irs', # # 'gs', 'win', 'loss', 'hold', 'sv', 'bsv', 'week', 'game'] # # # # new_bat_stats = [] # # new_pit_stats = [] # # final_box_away = {'r': 0, 'h': 0, 'e': 0, 'ip': 0} # # final_box_home = {'r': 0, 'h': 0, 'e': 0, 'ip': 0} # # final_wp = None # # final_lp = None # # final_holds = [] # # final_sv = None # # final_bsv = [] # # final_doubles = [] # # final_triples = [] # # final_homeruns = [] # # final_sbs = [] # # final_cscs = [] # # # # # Read batting stats # # for group in [away_bats, home_bats]: # # for line in group: # # if line[0]: # # # Dictionary to hold data to be passed to db for BatStat model # # this_batter = {'season': current['season']} # # # # # Keeping count so we can add stat name and data from sheet into this_batter dict # # for count in range(len(bat_stats)): # # if line[count] != '' and line[count] != '#REF' and line[count] != 0: # # this_batter[bat_stats[count]] = line[count] # # # # # Add this_batter to collection new_bat_stats # # try: # # this_batter['player_id'] = self.player_list[line[0].lower()] # # this_batter['team_id'] = away_team['id'] if line[1].lower() == away_team['abbrev'].lower() \ # # else home_team['id'] # # # Check for pitcher int in position # # if this_batter['pos'] in pit_nums: # # this_batter['pos'] = 'P' # # this_bat_stat = BatStat.parse_obj(this_batter) # # new_bat_stats.append(this_bat_stat.dict()) # # # # # Get stats for news-ticker # # if this_batter['team_id'] == away_team['id']: # # final_box_away['r'] += this_bat_stat.run # # final_box_away['h'] += this_bat_stat.hit # # final_box_away['e'] += this_bat_stat.error # # else: # # final_box_home['r'] += this_bat_stat.run # # final_box_home['h'] += this_bat_stat.hit # # final_box_home['e'] += this_bat_stat.error # # # # if this_bat_stat.double: # # final_doubles.append((this_batter['player_id'], this_bat_stat.double)) # # if this_bat_stat.triple: # # final_triples.append((this_batter['player_id'], this_bat_stat.triple)) # # if this_bat_stat.hr: # # final_homeruns.append((this_batter['player_id'], this_bat_stat.hr)) # # if this_bat_stat.sb: # # final_sbs.append((this_batter['player_id'], this_bat_stat.sb)) # # if this_bat_stat.csc: # # final_cscs.append((this_batter['player_id'], this_bat_stat.csc)) # # # # except Exception as e: # # errors.append(f'{line[0]}: {e}') # # # # # Read pitching stats # # for group in [away_arms, home_arms]: # # for line in group: # # if line[0]: # # # Dictionary to hold data for PitStat model # # this_pitcher = {'season': current['season']} # # # # # Keeping count so we can add stat name and data from sheet into this_pitcher dict # # for count in range(len(pit_stats)): # # if line[count] != '' and line[count] != '#REF' and line[count] != 0: # # this_pitcher[pit_stats[count]] = line[count] # # # # # Add this_pitcher to collection new_pit_stats # # try: # # this_pitcher['player_id'] = self.player_list[line[0].lower()] # # this_pitcher['team_id'] = away_team['id'] if line[1].lower() == away_team['abbrev'].lower() \ # # else home_team['id'] # # this_pit_stat = PitStat.parse_obj(this_pitcher) # # # # # Update IP to an even third # # first_digit = f'{this_pit_stat.ip % 1}'[2] # # if first_digit == '0': # # this_pit_stat.ip = math.floor(this_pit_stat.ip) # # elif first_digit in ['1', '3']: # # this_pit_stat.ip = math.floor(this_pit_stat.ip) + (1/3) # # else: # # this_pit_stat.ip = math.floor(this_pit_stat.ip) + (2/3) # # # # new_pit_stats.append(this_pit_stat.dict()) # # # # # Get stats for news-ticker # # if this_pit_stat.win: # # final_wp = this_pit_stat.player_id # # if this_pit_stat.loss: # # final_lp = this_pit_stat.player_id # # if this_pit_stat.sv: # # final_sv = this_pit_stat.player_id # # if this_pit_stat.bsv: # # final_bsv.append(this_pit_stat.player_id) # # if this_pit_stat.hold: # # final_holds.append(this_pit_stat.player_id) # # if this_pitcher['team_id'] == away_team['id']: # # final_box_away['ip'] += this_pit_stat.ip # # else: # # final_box_home['ip'] += this_pit_stat.ip # # except Exception as e: # # errors.append(f'{line[0]}: {e}') # # # # # Error checks # # await ctx.send('Just finished reading the scorecard. Now to look for all of your mistakes...') # # async with ctx.typing(): # # for line in new_bat_stats: # # b_counts['sbc'] += line['sbc'] # # b_counts['csc'] += line['csc'] # # b_counts['sb'] += line['sb'] # # b_counts['cs'] += line['cs'] # # b_counts['so'] += line['so'] # # b_counts['bb'] += line['bb'] + line['ibb'] # # b_counts['run'] += line['run'] # # b_counts['rbi'] += line['rbi'] # # b_counts['xba'] += line['xba'] # # b_counts['xbt'] += line['xbt'] # # b_counts['raa'] += line['raa'] # # b_counts['rto'] += line['rto'] # # if line['pos'] not in positions: # # errors.append(f'{line["pos"]} not a valid position') # # for line in new_pit_stats: # # logging.info(f'line: {line}') # # p_counts['gs'] += line['gs'] # # p_counts['win'] += line['win'] # # p_counts['loss'] += line['loss'] # # p_counts['bb'] += line['bb'] # # p_counts['so'] += line['so'] # # p_counts['run'] += line['run'] # # p_counts['erun'] += line['erun'] # # p_counts['ir'] += line['ir'] # # p_counts['irs'] += line['irs'] # # # # if b_counts['sbc'] != b_counts['sb'] + b_counts['cs']: # # errors.append(f'There are {b_counts["sbc"]} stolen base attempts (SBa), but {b_counts["sb"]} SB and ' # # f'{b_counts["cs"]} CS.') # # if b_counts['csc'] != b_counts['cs']: # # errors.append(f'There are {b_counts["sbc"]} catcher caught stealings (CSc), but ' # # f'{b_counts["cs"]} baserunner CS.') # # if b_counts['so'] != p_counts['so']: # # errors.append(f'There are {b_counts["so"]} batter strikeouts, but {p_counts["so"]} pitcher strikeouts.') # # if b_counts['bb'] != p_counts['bb']: # # errors.append(f'There are {b_counts["bb"]} batter walks, but {p_counts["bb"]} pitcher.') # # if b_counts['run'] != p_counts['run']: # # errors.append(f'There are {b_counts["run"]} batter runs, but {p_counts["run"]} pitcher runs.') # # if b_counts['rbi'] > b_counts['run']: # # errors.append(f'There are {b_counts["rbi"]} runs batted in, but {b_counts["run"]} runs scored.') # # if b_counts['rto'] > b_counts['raa']: # # errors.append(f'There are {b_counts["rto"]} runners thrown out, but {b_counts["raa"]} runner ' # # f'advance attempts.') # # if b_counts['xbt'] > b_counts['xba']: # # errors.append(f'There are {b_counts["xbt"]} extra bases taken, but {b_counts["xba"]} extra ' # # f'base attempts.') # # if p_counts['erun'] > p_counts['run']: # # errors.append(f'There are {p_counts["erun"]} earned runs and {p_counts["run"]} total runs. ') # # if p_counts['gs'] != 2: # # errors.append(f'There should be 2 GS, but I see {p_counts["gs"]} of them.') # # if p_counts['win'] != 1: # # errors.append(f'There should be 1 W, but I see {p_counts["win"]} of them.') # # if p_counts['loss'] != 1: # # errors.append(f'There should be 1 L, but I see {p_counts["loss"]} of them.') # # if p_counts['irs'] > p_counts['ir']: # # errors.append(f'There are {p_counts["irs"]} inherited runners scored and {p_counts["ir"]} ' # # f'inherited runners.') # # # # # Post errors, if any, or post stats to db # # if len(errors) > 0: # # error_message = '\n- '.join(errors) # # await ctx.message.add_reaction('❌') # # await ctx.send(f'The following errors were found in your **wk{week_num}g{game_num}** scorecard. ' # # f'Please resolve them and resubmit - thanks!\n\n- {error_message}') # # logging.error(f'Scorecard errors: {error_message}') # # return # # else: # # bat_conf = await post_battingstats(new_bat_stats) # # pit_conf = await post_pitchingstats(new_pit_stats) # # # # if bat_conf and pit_conf: # # await ctx.message.add_reaction('✅') # # await ctx.send(f'You did it! I just logged the stats for **wk{week_num}g{game_num}**') # # # # # Update last games for pitchers # # for x in new_pit_stats: # # this_pitcher = await get_one_player(x["player_id"]) # # game_string = f'{float(x["ip"]):.2}IP w{x["week"]}g{x["game"]}' # # await patch_player(this_pitcher['id'], last_game=game_string, last_game2=this_pitcher['last_game']) # # else: # # await ctx.send('So the stats looked okay, but I had an accident when I tried to post them. They ' # # 'did not go through.') # # # # # Post scorecard to weekly archive # # card_url = f'<{SBA_BASE_URL}/scorecards/?season={current["season"]}&week={week_num}&game={game_num}' \ # # f'&away_abbrev={away_team["abbrev"]}&home_abbrev={home_team["abbrev"]}>' # # archive_channel = discord.utils.get(ctx.guild.text_channels, name=f'week-{week_num}-archive') # # if not archive_channel: # # overwrites = {ctx.guild.default_role: discord.PermissionOverwrite(send_messages=False, embed_links=False), # # ctx.guild.me: discord.PermissionOverwrite(send_messages=True)} # # archive_channel = await ctx.guild.create_text_channel( # # f'week-{week_num}-archive', # # overwrites=overwrites, # # category=discord.utils.get(ctx.guild.categories, name=f'Season {current["season"]} Archives'), # # position=0 # # ) # # # # await archive_channel.send( # # f'Game {game_num}: **{away_team["sname"]}** {await team_emoji(ctx, away_team)} ' # # f'{final_box_away["r"]} @ {final_box_home["r"]} ' # # f'{await team_emoji(ctx, home_team)} **{home_team["sname"]}**\n{card_url}') # # # # # Post box score to news-ticker # # extras = '' # # if final_box_home['ip'] > 9: # # extras = f' F/{math.floor(final_box_home["ip"])}' # # embed = get_team_embed( # # f'{away_team["sname"]} {final_box_away["r"]} @ ' # # f'{final_box_home["r"]} {home_team["sname"]}{extras}', # # team=away_team if final_box_away['r'] > final_box_home['r'] else home_team # # ) # # embed.description = f'Week {week_num} | Game {game_num}' # # # # embed.add_field( # # name='Box Score', # # value=f'```\n' # # f'Team | R | H | E |\n' # # f'{away_team["abbrev"]: <4} | {final_box_away["r"]: >2} | {final_box_away["h"]: >2} | ' # # f'{final_box_away["e"]: >2} |\n' # # f'{home_team["abbrev"]: <4} | {final_box_home["r"]: >2} | {final_box_home["h"]: >2} | ' # # f'{final_box_home["e"]: >2} |\n' # # f'```', # # inline=False # # ) # # # # wp = await get_one_player(final_wp) # # lp = await get_one_player(final_lp) # # if final_sv: # # sv = await get_one_player(final_sv) # # else: # # sv = None # # holds = [] # # bsvs = [] # # for x in final_holds: # # holds.append(await get_one_player(x)) # # for x in final_bsv: # # bsvs.append(await get_one_player(x)) # # # # pitching_string = f'WP: {wp["name"]}\n' \ # # f'LP: {lp["name"]}\n' \ # # f'{"HD: " if len(holds) > 0 else ""}' # # # # hold_string = '' # # count = 1 # # for x in holds: # # hold_string += f'{x["name"]}' # # if count < len(holds): # # hold_string += ', ' # # elif len(holds) > 0: # # hold_string += '\n' # # count += 1 # # pitching_string += hold_string # # # # if sv: # # pitching_string += f'SV: {sv["name"]}' # # # # embed.add_field(name='Pitching', value=pitching_string, inline=False) # # # # batting_string = '' # # count = 1 # # if len(final_doubles) > 0: # # batting_string += '2B: ' # # # # for x in final_doubles: # # player = await get_one_player(x[0]) # # batting_string += f'{player["name"]}' # # # # if x[1] > 1: # # batting_string += f' {x[1]}' # # # # if count < len(final_doubles): # # batting_string += ', ' # # else: # # batting_string += '\n' # # count += 1 # # # # count = 1 # # if len(final_triples) > 0: # # batting_string += '3B: ' # # # # for x in final_triples: # # player = await get_one_player(x[0]) # # batting_string += f'{player["name"]}' # # # # if x[1] > 1: # # batting_string += f' {x[1]}' # # # # if count < len(final_triples): # # batting_string += ', ' # # else: # # batting_string += '\n' # # count += 1 # # # # count = 1 # # if len(final_homeruns) > 0: # # batting_string += 'HR: ' # # # # for x in final_homeruns: # # player = await get_one_player(x[0]) # # batting_string += f'{player["name"]}' # # # # if x[1] > 1: # # batting_string += f' {x[1]}' # # # # if count < len(final_homeruns): # # batting_string += ', ' # # else: # # batting_string += '\n' # # count += 1 # # # # if len(batting_string) > 0: # # embed.add_field(name='Batting', value=batting_string, inline=False) # # # # baserunning_string = '' # # count = 1 # # if len(final_sbs) > 0: # # baserunning_string += 'SB: ' # # # # for x in final_sbs: # # player = await get_one_player(x[0]) # # baserunning_string += f'{player["name"]}' # # # # if x[1] > 1: # # baserunning_string += f' {x[1]}' # # # # if count < len(final_sbs): # # baserunning_string += ', ' # # else: # # baserunning_string += '\n' # # count += 1 # # # # count = 1 # # if len(final_cscs) > 0: # # baserunning_string += 'CSc: ' # # # # for x in final_cscs: # # player = await get_one_player(x[0]) # # baserunning_string += f'{player["name"]}' # # # # if x[1] > 1: # # baserunning_string += f' {x[1]}' # # # # if count < len(final_cscs): # # baserunning_string += ', ' # # else: # # baserunning_string += '\n' # # count += 1 # # # # if len(baserunning_string) > 0: # # embed.add_field(name='Baserunning', value=baserunning_string, inline=False) # # # # embed.add_field(name='Scorecard', value=card_url) # # embed.set_footer(text='Please share the highlights!') # # # # await send_to_channel( # # self.bot, # # 'sba-network-news', # # content=None, # # embed=embed # # ) # await ctx.send(f'Please run `/sba-submit` to submit scorecards.') # @commands.command(name='removestats', help='Remove scorecard') # @commands.has_any_role(SBA_PLAYERS_ROLE_NAME) # async def remove_stats_command(self, ctx, away_abbrev, home_abbrev, week_num, game_num): # current = await get_current() # # owner_team = await get_team_by_owner(current['season'], ctx.author.id) # away_team = await get_one_team(away_abbrev) # home_team = await get_one_team(home_abbrev) # # # Confirm teams and matchup # this_matchup = await get_schedule( # current['season'], away_abbrev=away_team['abbrev'], home_abbrev=home_team['abbrev'], week_start=week_num, # week_end=week_num # ) # if len(this_matchup) != 1: # await ctx.send(f'Hmm...it doesn\'t look like {away_team["abbrev"]} played {home_team["abbrev"]} in ' # f'week {week_num}.') # return # # # Confirm stats for game don't already exist # s_type = 'Regular' if current['week'] < current['playoffs_begin'] else 'Post' # old_home_bat = await get_battingstat( # season=current['season'], s_type=s_type, team_abbrev=home_team['abbrev'], week_start=week_num, # week_end=week_num, game_num=game_num) # old_away_bat = await get_battingstat( # season=current['season'], s_type=s_type, team_abbrev=away_team['abbrev'], week_start=week_num, # week_end=week_num, game_num=game_num) # old_home_arm = await get_pitchingstat( # season=current['season'], s_type=s_type, team_abbrev=home_team['abbrev'], week_start=week_num, # week_end=week_num, game_num=game_num) # old_away_arm = await get_pitchingstat( # season=current['season'], s_type=s_type, team_abbrev=away_team['abbrev'], week_start=week_num, # week_end=week_num, game_num=game_num) # # if len(old_home_bat) + len(old_away_bat) + len(old_home_arm) + len(old_away_arm) == 0: # await ctx.send('Good news: I don\'t see any stats for that game. Bad news: you seemed to think there ' # 'were some.') # return # # # Confirm submitting GM # if owner_team not in [home_team, away_team] and ctx.author.id != self.bot.owner_id: # await ctx.send(f'{await get_emoji(ctx, "squint")} Only a GM of the two teams can remove stats.') # return # # prompt = 'Are you sure? This will snap these stats out of existence.' # this_q = Question(self.bot, ctx.channel, prompt, 'yesno', 30) # resp = await this_q.ask([ctx.author]) # # if not resp: # await ctx.send('Whew. There for a second I thought you fucked up a scorecard. I\'ll leave this one be.') # return # # this_game = { # 'season': current['season'], # 'week': week_num, # 'game_num': game_num, # 'away_team_id': away_team['id'], # 'home_team_id': home_team['id'] # } # # await ctx.send('What a pain in my balls. Let\'s start by deleting the batting stats.') # async with ctx.typing(): # if await delete_battingstats(this_game): # await ctx.send('Batting stats are gone - now the pitching stats.') # # async with ctx.typing(): # if await delete_pitchingstats(this_game): # await ctx.send('Pitching stats are gone - now to recalculate everybody\'s season batting lines.') # # async with ctx.typing(): # if await recalc_batting_seasons(current['season'], away_team['id']): # if await recalc_batting_seasons(current['season'], home_team['id']): # await ctx.send('Batting lines are done - now to recalculate pitching lines.') # # async with ctx.typing(): # if await recalc_pitching_seasons(current['season'], away_team['id']): # if await recalc_pitching_seasons(current['season'], home_team['id']): # await ctx.send('Pitching lines are done - now to recalculate fielding lines.') # # async with ctx.typing(): # if await recalc_fielding_seasons(current['season'], away_team['id']): # await recalc_fielding_seasons(current['season'], home_team['id']) # # await ctx.send(f'All done. Don\'t suck next time {await get_emoji(ctx, "lakemonsters")}') @app_commands.command(name='branding', description='Update your team branding') @app_commands.guilds(discord.Object(id=os.environ.get('GUILD_ID'))) @app_commands.rename( team_image_url='team_logo_url', mil_team_image_url='minor_league_logo_url', ) @app_commands.describe( color_hex='Color hex code to use for your team', team_image_url='URL ending in .png or .jpg of your team logo', mil_color_hex='Color hex code to use for your minor league team', mil_team_image_url='URL ending in .png or .jpg of your minor league team logo', dice_color_hex='Color hex code to use for your dice rolls', ) @app_commands.checks.has_any_role(SBA_PLAYERS_ROLE_NAME) async def branding_slash_command( self, interaction: discord.Interaction, color_hex: str = None, team_image_url: str = None, mil_color_hex: str = None, mil_team_image_url: str = None, dice_color_hex: str = None): current = await get_current() team = await get_team_by_owner(current['season'], interaction.user.id) mil_team = await get_one_team(f'{team["abbrev"]}MiL', current['season']) team_role = get_team_role(interaction, team) errors = [] show_mil = False show_dice = False if not team or not team_role: await interaction.response.send_message( f'Do you have a team here? You don\'t look familiar. {await get_emoji(interaction, "realeyes")}' ) return if color_hex is not None: try: color_int = int(color_hex, 16) await team_role.edit(colour=color_int) await patch_team(team, color=color_hex) except Exception as e: logging.info(f'Error setting {team["sname"]} color to {color_hex}') errors.append(f'- Error setting {team["sname"]} color to {color_hex}:\n{e}\n\n') if team_image_url is not None: if requests.get(team_image_url, timeout=0.5).status_code != 200: errors.append(f'- I wasn\'t able to pull that image. Was it a public URL?\n\n') else: await patch_team(team, thumbnail=team_image_url) if mil_color_hex is not None: try: await patch_team(mil_team, color=color_hex) show_mil = True except Exception as e: logging.info(f'Error setting {team["sname"]} color to {color_hex}') errors.append(f'- Error setting {team["sname"]} color to {color_hex}:\n{e}\n\n') if mil_team_image_url is not None: if requests.get(team_image_url, timeout=0.5).status_code != 200: errors.append(f'- I wasn\'t able to pull that image. Was it a public URL?\n\n') else: await patch_team(mil_team, thumbnail=mil_team_image_url) show_mil = True if dice_color_hex is not None: try: await patch_team(team, dice_color=dice_color_hex) show_dice = True except Exception as e: logging.info(f'Error setting {team["sname"]} color to {color_hex}') errors.append(f'- Error setting {team["sname"]} color to {color_hex}:\n{e}\n\n') team = await get_one_team(team['id'], season=current['season']) major_embed = get_team_embed(f'{team["lname"]} Test', team=team) major_embed.add_field( name='Little Test Data', value='Run the command again if you want to change anything!' ) embeds = [major_embed] if show_mil: mil_team = await get_one_team(mil_team['id']) mil_embed = get_team_embed(f'{mil_team["lname"]} Test', team=mil_team) mil_embed.add_field( name='Little Test Data', value='Run the command again if you want to change anything!' ) embeds.append(mil_embed) if show_dice: logging.info(f'entering show_dice') team['color'] = team['dice_color'] dice_embed = get_team_embed(f'{team["lname"]} Dice Test', team=team) logging.info(f'got base embed: {dice_embed}') dice_embed.add_field( name='Little Test Data', value='This is what we\'ve got for your dice rolls!' ) logging.info(f'done with embed: {dice_embed}') embeds.append(dice_embed) await interaction.response.send_message(content=None, embeds=embeds) # @commands.command(name='setcolor', help='Set team color') # @commands.has_any_role(SBA_PLAYERS_ROLE_NAME) # async def set_color_command(self, ctx, color_code): # current = await get_current() # team = await get_team_by_owner(current['season'], ctx.author.id) # team_role = get_team_role(ctx, team) # color_int = int(color_code, 16) # # if not team or not team_role: # await ctx.send(f'Do you have a team here? You don\'t look familiar. {await get_emoji(ctx, "realeyes")}') # return # # await team_role.edit(colour=color_int) # await patch_team(team, color=color_code) # team = await get_team_by_owner(current['season'], ctx.author.id) # # embed = get_team_embed(f'{team["lname"]} Test', team=team) # embed.add_field( # name='Reminder', # value='Don\'t forget to set your team thumbnail image with the !setthumbnail command!' # ) # await ctx.send(content='Got it! What do you think?', embed=embed) # # @commands.command(name='setthumbnail', help='Set team pic') # @commands.has_any_role(SBA_PLAYERS_ROLE_NAME) # async def set_thumbnail_command(self, ctx, thumbnail_url): # current = await get_current() # team = await get_team_by_owner(current['season'], ctx.author.id) # team_role = get_team_role(ctx, team) # # if not team or not team_role: # await ctx.send(f'Do you have a team here? You don\'t look familiar. {await get_emoji(ctx, "realeyes")}') # return # # if requests.get(thumbnail_url, timeout=0.5).status_code != 200: # await ctx.send('I wasn\'t able to pull that thumbnail. Was it a public URL?') # # await patch_team(team, thumbnail=thumbnail_url) # team = await get_team_by_owner(current['season'], ctx.author.id) # # embed = get_team_embed(f'{team["lname"]} Test', team=team) # embed.add_field( # name='Reminder', # value='Don\'t forget to set your team color with the !setcolor command!' # ) # # await ctx.send(content='Got it! What do you think?', embed=embed) # # @commands.command(name='setminorthumbnail', help='Set minor team pic') # @commands.has_any_role(SBA_PLAYERS_ROLE_NAME) # async def set_minor_pic_command(self, ctx, thumbnail_url): # current = await get_current() # team = await get_team_by_owner(current['season'], ctx.author.id) # minor_team = await get_one_team(team['id'] + 2) # # if not minor_team: # await ctx.send(f'Do you have a team here? You don\'t look familiar. {await get_emoji(ctx, "realeyes")}') # return # # if requests.get(thumbnail_url, timeout=0.5).status_code != 200: # await ctx.send('I wasn\'t able to pull that thumbnail. Was it a public URL?') # # await patch_team(minor_team, thumbnail=thumbnail_url) # minor_team = await get_one_team(team['id'] + 2) # # embed = get_team_embed(f'{minor_team["sname"]} Test', team=minor_team) # embed.add_field( # name='Reminder', # value='Don\'t forget to set your team color with the !setminorcolor command!' # ) # await ctx.send(content='Got it! What do you think?', embed=embed) # # @commands.command(name='setminorcolor', help='Set minor team color') # @commands.has_any_role(SBA_PLAYERS_ROLE_NAME) # async def set_minor_color_command(self, ctx, color_code): # current = await get_current() # team = await get_team_by_owner(current['season'], ctx.author.id) # minor_team = await get_one_team(team['id'] + 2) # # if not minor_team: # await ctx.send(f'Do you have a team here? You don\'t look familiar. {await get_emoji(ctx, "realeyes")}') # return # # await patch_team(minor_team, color=color_code) # minor_team = await get_one_team(team['id'] + 2) # team = await get_team_by_owner(current['season'], ctx.author.id) # # embed = get_team_embed(f'{minor_team["sname"]} Test', team=minor_team) # embed.add_field( # name='Reminder', # value='Don\'t forget to set your team thumbnail image with the !setminorthumbnail command!' # ) # await ctx.send(content='Got it! What do you think?', embed=embed) # # @commands.command(name='setdicecolor', help='Set dice embed color') # @commands.has_any_role(SBA_PLAYERS_ROLE_NAME) # async def set_dice_color_command(self, ctx, color_code): # current = await get_current() # team = await get_team_by_owner(current['season'], ctx.author.id) # # await patch_team(team, dice_color=color_code) # embed = discord.Embed( # title=f'Dice Color: {color_code}', # color=int(color_code, 16) # ) # embed.add_field( # name='Reminder', # value='Any dice rolled in your home stadium will use this color!' # ) # await ctx.send(content=None, embed=embed) @commands.command(name='picks', aliases=['mypicks', 'draftpicks'], help='See your picks') async def picks_command(self, ctx, *team_abbrev): await ctx.send('Go away.') return current = await get_current() if team_abbrev: team = await get_one_team(team_abbrev[0]) else: team = await get_team_by_owner(current['season'], ctx.author.id) if not team: await ctx.send('I don\'t know what team you\'re looking for.') return raw_picks = await get_draftpicks(season=5, owner_team=team, team_season=5) logging.info(f'raw_picks: {raw_picks}') try: all_picks = dict(sorted(raw_picks.items(), key=lambda item: item[1]["overall"])) except TypeError as e: all_picks = dict(sorted(raw_picks.items(), key=lambda item: item[1]["round"])) pick_string = '' for x in all_picks: squiggles = '~~' if all_picks[x]['player'] else '' selection = f'- {all_picks[x]["player"]["name"]}' if all_picks[x]["player"] else '' overall = f'#{all_picks[x]["overall"]} - ' if all_picks[x]["overall"] else '' pick_string += f'{squiggles}{overall}{all_picks[x]["origowner"]["abbrev"]} {all_picks[x]["round"]}' \ f'{squiggles} {selection}\n' embed = get_team_embed(f'{team["lname"]}', team=team) embed.add_field(name=f'Season {current["season"]} Draft Picks', value=pick_string) await ctx.send(content=None, embed=embed) # @commands.command(name='fixscore', help='Change result') # @commands.has_any_role(SBA_PLAYERS_ROLE_NAME) # async def fix_score_command( # self, ctx, away_team, away_score: int, home_team, home_score: int, week_num: int, game_num: int): # current = await get_current() # week_games = await get_results(current['season'], away_abbrev=away_team, home_abbrev=home_team, week=week_num) # this_game = None # # for x in week_games: # if week_games[x]['game'] == game_num: # this_game = week_games[x] # break # # if this_game is None: # await ctx.send('I don\'t see a record of that game. Make sure you\'ve got the week and game number right. ' # 'If so, go ahead and log it with the !result command') # return # # if this_game['awayscore'] == away_score and this_game['homescore'] == home_score: # await ctx.send('Good news, everyone! That is already the score I have listed!') # return # # await ctx.send(f'I\'ve got that game listed as {this_game["awayteam"]["abbrev"]} ' # f'{await team_emoji(ctx, this_game["awayteam"])} {this_game["awayscore"]} @ ' # f'{this_game["homescore"]} {await team_emoji(ctx, this_game["hometeam"])} ' # f'{this_game["hometeam"]["abbrev"]}') # prompt = f'Would you like to change this to {this_game["awayteam"]["abbrev"]} ' \ # f'{await team_emoji(ctx, this_game["awayteam"])} {away_score} @ ' \ # f'{home_score} {await team_emoji(ctx, this_game["hometeam"])} {this_game["hometeam"]["abbrev"]}?' # this_q = Question(self.bot, ctx.channel, prompt, 'yesno', 30) # resp = await this_q.ask([ctx.author]) # # if not resp: # await ctx.send('Mmkay. I\'ll leave it alone for now.') # return # else: # if await patch_result(this_game['id'], away_score=away_score, home_score=home_score): # await ctx.message.add_reaction('✅') # await ctx.send(f'{get_team_role(ctx, this_game["awayteam"]).mention} ' # f'{get_team_role(ctx, this_game["hometeam"]).mention}') # await ctx.send(random_conf_gif()) @commands.command(name='newaward', help='Grant award') @commands.has_any_role('Awards Team', 'Da Commish') async def new_award_command(self, ctx, *, award_name): # f'{"In-Season" if in_or_off.lower() == "in" else "Off-Season"}' current = await get_current() award = { 'name': award_name, 'season': None, 'timing': None, 'manager1': None, 'manager2': None, 'player': None, 'team': None, 'image': None, 'invalid': False } async def add_recipient(search_string): try: this_team = await get_one_team(search_string, season=award['season']) award['team'] = this_team except ValueError: try: this_manager = await get_one_manager(search_string) if not award['manager1']: award['manager1'] = this_manager else: award['manager2'] = this_manager except ValueError: try: search_name = await fuzzy_player_search( ctx, ctx.channel, self.bot, search_string, self.player_list) this_player = await get_one_player(search_name, season=award['season']) award['player'] = this_player except ValueError: try: this_player = await get_one_player(search_string, season=award['season']) award['player'] = this_player except ValueError: await ctx.send(f'I do not recognize **{search_string}**. Will you check the spelling and ' f'try again?') def get_embed(): this_embed = discord.Embed(title=award['name']) this_embed.description = f'{award["timing"]} - S{award["season"]}' if award['manager1']: this_embed.add_field(name='Manager', value=award['manager1']) if award['manager2']: this_embed.add_field(name='Manager', value=award['manager2']) if award['player']: this_embed.add_field(name='Player', value=f'{award["player"]["name"]}') if award['team']: this_embed.add_field(name='Team', value=f'{award["team"]["lname"]}') if award['image']: try: this_embed.set_image(url=award['image']) except: award['invalid'] = True this_embed.add_field(name='Image', value='Invalid URL') return this_embed prompt = f'Is this for season {current["season"]}?' this_q = Question(self.bot, ctx.channel, prompt, 'yesno', timeout=45) resp = await this_q.ask([ctx.author]) if resp is None: await ctx.send('Think on it. Get back to me.') return elif resp: award['season'] = current['season'] else: prompt = 'Please enter the season for this award.' this_q = Question(self.bot, ctx.channel, prompt, 'int', timeout=45) resp = await this_q.ask([ctx.author]) if not resp: await ctx.send('Think on it. Get back to me.') return else: award['season'] = resp prompt = f'Is this an In-Season award (as opposed to off-season)?' this_q = Question(self.bot, ctx.channel, prompt, 'yesno', timeout=45) resp = await this_q.ask([ctx.author]) if resp is None: await ctx.send('Think on it. Get back to me.') return elif resp: award['timing'] = 'In-Season' else: award['timing'] = 'Off-Season' await ctx.send('Got it - I\'ll put this down as an Off-Season award') prompt = 'Is this the start you wanted?' this_q = Question(self.bot, ctx.channel, prompt, 'yesno', timeout=45, embed=get_embed()) resp = await this_q.ask([ctx.author]) if not resp: await ctx.send('No worries - run `!newaward Award_Name` again to rename it.') return # Get team/player/managers while True: prompt = 'Please enter the team abbreviation, player name, or manager name of the recipient.' this_q = Question(self.bot, ctx.channel, prompt, 'text', timeout=45) resp = await this_q.ask([ctx.author]) if resp is None: await ctx.send('You think on it and hit me up when you\'re ready.') return else: await add_recipient(resp) await ctx.send('Here is the current award', embed=get_embed()) prompt = 'Would you like to (re)enter a recipient?' this_q = Question(self.bot, ctx.channel, prompt, 'yesno', timeout=45) resp = await this_q.ask([ctx.author]) if resp is None: await ctx.send('We can hold off on this for now. Let me know when you\'re ready to start again.') return elif not resp: break # Get image URL while True: prompt = 'Would you like to (re)enter an image URL for this award?' this_q = Question(self.bot, ctx.channel, prompt, 'yesno', timeout=45, embed=get_embed()) resp = await this_q.ask([ctx.author]) if not resp: break else: prompt = 'Please enter the image URL.' this_q = Question(self.bot, ctx.channel, prompt, 'url', timeout=45) resp = await this_q.ask([ctx.author]) if resp is None: await ctx.send('Okey doke, nevermind. I get it. It\'s fine. We only did all this work for nothing. ' 'Let me know when you want to start again.') return elif not resp: await ctx.send(f'**{resp}** is not a valid URL.') else: award['image'] = resp prompt = 'Would you like to submit this award?' this_q = Question(self.bot, ctx.channel, prompt, 'yesno', timeout=45, embed=get_embed()) resp = await this_q.ask([ctx.author]) if not resp: await ctx.send('Really? After all the ti- nevermind. Fine. Kill it. It\'s over. Bye.') return else: await post_award(award) await ctx.send(random_conf_gif()) @commands.command(name='record', help='Record through week num') async def record_command(self, ctx, team_abbrev, week_num: int): this_team = await get_one_team(team_abbrev) this_record = await get_team_record(this_team, week_num) await ctx.send(f'The {this_team["sname"]} were ({this_record["w"]}-{this_record["l"]}) through ' f'week {week_num}.') @commands.command(name='vc', aliases=['voice', 'gameplay'], help='Get voice channel') @commands.has_any_role(SBA_PLAYERS_ROLE_NAME, 'Paper Dynasty Players') async def voice_channel_command(self, ctx): prompt = 'Would you like to get a gameplay channel?' this_q = Question(self.bot, ctx.channel, prompt, qtype='yesno', timeout=15) resp = await this_q.ask([ctx.author]) if not resp: await ctx.send('Fine. I bet they didn\'t wanna talk to you anyway.') return else: overwrites = {ctx.guild.default_role: discord.PermissionOverwrite(speak=True)} channel_name = f'Gameplay {random_codename()}' this_vc = await ctx.guild.create_voice_channel( channel_name, overwrites=overwrites, category=discord.utils.get(ctx.guild.categories, name=f'Voice Channels') ) logging.info(f'Just created voice channel: {channel_name} for {ctx.author}') await ctx.send(f'Just created {this_vc} for you!') while True: await asyncio.sleep(900) if len(this_vc.members) == 0: await this_vc.delete() logging.info(f'Just deleted voice channel: {channel_name}') break @commands.command(name='private', help='Get private vc') @commands.has_any_role(SBA_PLAYERS_ROLE_NAME) async def private_vc_command(self, ctx): current = await get_current() this_team = await get_team_by_owner(current['season'], ctx.author.id) async def get_other_team(): prompt = f'Please enter the abbrev of the team you are playing.' this_q = Question(self.bot, ctx.channel, prompt, qtype='text', timeout=15) resp = await this_q.ask([ctx.author]) if not resp: await ctx.send('You keep thinking about it and hit me up later if you figure it out.') return None else: other_team = await get_one_team(resp) if not other_team: await ctx.send(f'What\'s a **{resp}**? If you could go ahead and run this command again, that\'d ' f'be great.') return None else: return other_team if not this_team: await ctx.send('Hmm...I can\'t find your team. Are you from around here?') return try: this_matchup = await get_one_schedule( season=current['season'], team_abbrev1=this_team['abbrev'], week=current['week'] ) except ValueError as e: other_team = await get_other_team() if not other_team: return channel_name = f'{this_team["abbrev"]} vs {other_team["abbrev"]} Muted' else: if this_team == this_matchup['awayteam']: other_team = this_matchup['hometeam'] else: other_team = this_matchup['awayteam'] channel_name = f'{this_matchup["awayteam"]["sname"]} @ {this_matchup["hometeam"]["sname"]} Muted' prompt = f'Would you like to get a private voice channel for {this_team["abbrev"]} and {other_team["abbrev"]}?' this_q = Question(self.bot, ctx.channel, prompt, qtype='yesno', timeout=15) resp = await this_q.ask([ctx.author]) if resp is None: await ctx.send('Fine. I bet they didn\'t wanna talk to you anyway.') return elif not resp: other_team = await get_other_team() if not other_team: return channel_name = f'{this_team["abbrev"]} vs {other_team["abbrev"]}' this_team_role = discord.utils.get(ctx.guild.roles, name=f'{this_team["lname"]}') other_team_role = discord.utils.get(ctx.guild.roles, name=f'{other_team["lname"]}') overwrites = {ctx.guild.default_role: discord.PermissionOverwrite(speak=False), this_team_role: discord.PermissionOverwrite(speak=True), other_team_role: discord.PermissionOverwrite(speak=True)} this_vc = await ctx.guild.create_voice_channel( channel_name, overwrites=overwrites, category=discord.utils.get(ctx.guild.categories, name=f'Voice Channels') ) await ctx.send(f'Just created {this_vc} for you!') while True: await asyncio.sleep(900) if len(this_vc.members) == 0: await this_vc.delete() break @commands.command(name='headshot', aliases=['hs'], help='Set headshot pic') @commands.has_any_role(SBA_PLAYERS_ROLE_NAME) async def headshot_command(self, ctx, url, *, player_name): if ctx.channel.name == 'season-6-chat': await ctx.send('Not in season 6 chat, dumbass.') return current = await get_current() this_team = await get_team_by_owner(current['season'], ctx.author.id) if not this_team: await ctx.send('Hmm...I can\'t find your team. Are you from around here?') return player = await get_one_player( await fuzzy_player_search(ctx, ctx.channel, self.bot, player_name, self.player_list.keys()) ) player_embed = await get_player_embed(player, current) player_embed.set_thumbnail(url=url) prompt = 'Would you like to save this image?' this_q = Question(self.bot, ctx.channel, prompt, 'yesno', 15, player_embed) resp = await this_q.ask([ctx.author]) if not resp: await ctx.send('That\'s okay. It wasn\'t a very good picture anyway.') return else: await patch_player(player['id'], headshot=url) await ctx.send(random_conf_word()) @commands.command(name='fancycard', aliases=['fc'], help='Set vanity card') @commands.has_any_role(SBA_PLAYERS_ROLE_NAME) async def vanity_card_command(self, ctx, url, *, player_name): if ctx.channel.name == 'season-6-chat': await ctx.send('Not in season 6 chat, dumbass.') return current = await get_current() this_team = await get_team_by_owner(current['season'], ctx.author.id) if not this_team: await ctx.send('Hmm...I can\'t find your team. Are you from around here?') return player = await get_one_player( await fuzzy_player_search(ctx, ctx.channel, self.bot, player_name, self.player_list.keys()) ) player_embed = await get_player_embed(player, current) player_embed.set_thumbnail(url=url) prompt = 'Would you like to save this image?' this_q = Question(self.bot, ctx.channel, prompt, 'yesno', 15, player_embed) resp = await this_q.ask([ctx.author]) if not resp: await ctx.send('That\'s okay. It wasn\'t a very good picture anyway.') return else: await patch_player(player['id'], vanity_card=url) await ctx.send(random_conf_word()) @commands.command(name='getfc', help='Get last season vanity card') @commands.has_any_role(SBA_PLAYERS_ROLE_NAME) async def get_vanity_card_command(self, ctx, *, player_name): if ctx.channel.name == 'season-5-chat': await ctx.send('Not in season 5 chat, dumbass.') return current = await get_current() this_team = await get_team_by_owner(current['season'], ctx.author.id) if not this_team: await ctx.send('Hmm...I can\'t find your team. Are you from around here?') return player = await get_one_player( await fuzzy_player_search(ctx, ctx.channel, self.bot, player_name, self.player_list.keys()) ) old_player = await get_one_player(player["name"], season=current["season"]-1) await patch_player( pid=player["id"], vanity_card=old_player["vanity_card"] ) player["vanity_card"] = old_player["vanity_card"] player_embed = await get_player_embed(player, current) await ctx.send(content=None, embed=player_embed) @commands.command(name='charts', aliases=['chart'], help='Run `/charts` for all charts') async def legacy_charts_command(self, ctx): await ctx.send(f'Run `/charts` for all charts') @app_commands.command(name='charts') async def chart_command(self, interaction: discord.Interaction, chart_name: Literal[ 'rest', 'sac-bunt', 'squeeze-bunt', 'rob-hr', 'defense-matters', 'block-plate', 'hit-and-run', 'g1', 'g2', 'g3', 'groundball']): gb_url = 'https://sombaseball.ddns.net/static/images/season04/ground-ball-chart' all_charts = { 'rest': [f'{SBA_IMAGE_URL}/season05/charts/rest.png'], 'sac-bunt': [ f'{SBA_IMAGE_URL}/season05/charts/sac-bunt.png', f'{SBA_IMAGE_URL}/season05/charts/sac-bunt-help.png' ], 'squeeze-bunt': [ f'{SBA_IMAGE_URL}/season05/charts/squeeze-bunt.png', f'{SBA_IMAGE_URL}/season05/charts/squeeze-bunt-help.png' ], 'rob-hr': [f'{SBA_IMAGE_URL}/season05/charts/rob-hr.png'], 'defense-matters': [f'{SBA_IMAGE_URL}/season05/charts/defense-matters.png'], 'block-plate': [f'{SBA_IMAGE_URL}/season05/charts/block-plate.png'], 'hit-and-run': [ f'{SBA_IMAGE_URL}/season05/charts/hit-and-run.png', f'{SBA_IMAGE_URL}/season05/charts/hit-and-run-pitcher.png' ], 'g1': [f'{gb_url}-g1.png', f'{gb_url}01.png', f'{gb_url}02.png'], 'g2': [f'{gb_url}-g2.png', f'{gb_url}01.png', f'{gb_url}02.png'], 'g3': [f'{gb_url}-g3.png', f'{gb_url}01.png', f'{gb_url}02.png'], 'groundball': [f'{gb_url}01.png', f'{gb_url}02.png'] } first = True for link in all_charts[chart_name]: if first: await interaction.response.send_message(link) first = False else: await interaction.followup.send(link) @commands.command(name='pitcherbatting', aliases=['pbat', 'pitbat'], help='Show specific pitcher batting card') @commands.has_any_role(SBA_PLAYERS_ROLE_NAME, PD_PLAYERS_ROLE_NAME) async def pitcher_batting_command(self, ctx: commands.Context, card_num: int = 1): if card_num > 8: await ctx.send(f'I only have pitcher batting cards 1 through 8. Why don\'t you try again.') return if card_num < 1: await ctx.send(f'I only have pitcher batting cards 1 through 8. Why don\'t you try again.') return team = await get_team_by_owner(SBA_SEASON, ctx.author.id) embed = get_team_embed(f'Pitcher Batting Card #{card_num}', team=team, thumbnail=False) embed.set_image(url=f'{SBA_BASE_URL}/static/images/pitbat/card-{card_num}.png') await ctx.send(content=None, embed=embed) @app_commands.command(name='pitupdate', description='Mod: Update pitcher ratings') @app_commands.checks.has_any_role('Da Commish') async def pit_update_slash( self, interaction: discord.Interaction, player_name: str, swar: float = None, injury_games: int = None): player = await get_one_player( await fuzzy_player_search(interaction, interaction.channel, self.bot, player_name, self.player_list), ) current = await get_current() await patch_player( player['id'], wara=swar if swar is not None else player['wara'], injury_rating=f'{player["injury_rating"][:2]}{injury_games}' if injury_games is not None else player["injury_rating"] ) new_player = await get_one_player(player['id']) await interaction.response.send_message(content=None, embed=await get_player_embed(new_player, current)) @app_commands.command(name='keepers', description='Mod: Set team keepers') @app_commands.checks.has_any_role('Da Commish') async def set_keepers_slash( self, interaction: discord.Interaction, team_abbrev: str, keep1: str = None, keep2: str = None, keep3: str = None, keep4: str = None, keep5: str = None, keep6: str = None, keep7: str = None): team = await get_one_team(team_abbrev) keepers = [] keeper_string = '' keeper_swar = 0 def get_pos_abbrev(position): if 'B' in position: return 'IF' if 'F' in position: return 'OF' if 'P' in position: return 'P' if position == 'C': return 'C' return 'DH' for x in [keep1, keep2, keep3, keep4, keep5, keep6, keep7]: if x: this_p = await get_one_player( await fuzzy_player_search(interaction, interaction.channel, self.bot, x, self.player_list) ) keepers.append(this_p) keeper_string += f'{get_pos_abbrev(this_p["pos_1"])} - {this_p["name"]} ({this_p["wara"]:.2f})\n' keeper_swar += this_p['wara'] await interaction.response.send_message(content=f'{team["sname"]} Keepers:\n{keeper_string}') all_players = db_get('players', api_ver=3, params=[('team_abbrev', team['abbrev'])]) logging.info(f'all_players: {all_players}') fa = await get_one_team('FA') for y in all_players['players']: if y not in keepers: await patch_player(y['id'], team_id=fa['id']) await interaction.channel.send( f'Just yeeted **{len(all_players["players"]) - len(keepers)}** players into the sun!' ) embed = get_team_embed(title=f'{team["lname"]} Keepers', team=team) embed.add_field(name=f'Keepers', value=keeper_string) embed.add_field(name='Total sWAR', value=f'{keeper_swar:.2f}') await send_to_channel(self.bot, 'sba-network-news', content=None, embed=embed) group_publish = app_commands.Group(name='publish', description='Make a scorecard publicly accessible') @group_publish.command(name='josef') @app_commands.describe(sheet_url='The full URL of your publicly shared scorecard') async def pub_josef_slash(self, interaction: discord.Interaction, sheet_url: str): sheets = pygsheets.authorize(service_file='storage/major-domo-service-creds.json') try: if 'https://' in sheet_url: scorecard = sheets.open_by_url(sheet_url).worksheet_by_title('ASCII') else: scorecard = sheets.open_by_key(sheet_url).worksheet_by_title('ASCII') except Exception as e: await interaction.response.send_message( 'Frick. I wasn\'t able to publish that card. Is that card ID correct?' ) return self.scorecards[f'{interaction.channel_id}'] = scorecard await interaction.response.send_message( f'Your scorecard has been published. Anyone may now run `/scorebug` in ' f'this channel to get the scorebug.') @app_commands.command(name='scorebug', description='Pull the scorebug for the game in this channel') @commands.has_any_role(SBA_PLAYERS_ROLE_NAME, PD_PLAYERS_ROLE_NAME) async def scorebug_slash(self, interaction: discord.Interaction): if not self.scorecards: await interaction.response.send_message( 'Uhh...I don\'t see any games in this channel. You in the right place?' ) return this_scorecard = self.scorecards[f'{interaction.channel_id}'] if not this_scorecard: this_game = get_one_game(channel_id=interaction.channel_id) if not this_game: await interaction.response.send_message( 'Uhh...I don\'t see any games in this channel. You in the right place?' ) return embed = self.bot.get_cog('Gameplay').get_game_state_embed(this_game, full_length=False) await interaction.response.send_message(content=None, embed=embed) score_text = this_scorecard.get_value('A1') await interaction.response.send_message(score_text) async def setup(bot): await bot.add_cog(Players(bot))