async def on_slash_command_error(ctx: SlashContext, ex: Exception): def format_traceback(tback: list): return "".join(tback).replace("Aaron", "Secret") if isinstance(ex, discord.errors.NotFound): return log(f"Skipping a NotFound error", 1) elif isinstance(ex, (UserError, AssertionError)): embed = build_embed( title="Husker Bot User Error", description="An error occurred with user input", fields=[["Error Message", ex.message]], ) elif isinstance(ex, CommandError): embed = build_embed( title="Husker Bot Command Error", description="An error occurred with command processing", fields=[["Error Message", ex.message]], ) else: embed = build_embed( title="Husker Bot Command Error", description="An unknown error occurred", fields=[["Error Message", f"{ex.__class__}: {ex}"]], ) await ctx.send(embed=embed) traceback_raw = traceback.format_exception(etype=type(ex), value=ex, tb=ex.__traceback__) tback = format_traceback(traceback_raw) cmd = ctx.command sub_cmd = "" if ctx.subcommand_name is not None: sub_cmd = ctx.subcommand_name inputs = [] for key, value in ctx.data.items(): inputs.append(f"{key} = {value}") message = ( f"{ctx.author.mention} ({ctx.author.display_name}, {ctx.author_id}) received an unknown error!\n" f"\n" f"`/{cmd}{' ' + sub_cmd if sub_cmd is not None else ''} {inputs}`\n" f"\n" f"```\n{tback}\n```") try: gee = client.get_user(id=GEE_USER) await gee.send(content=message) except: await ctx.send(content=f"<@{GEE_USER}>\n{message}")
async def send_welcome_message(who: discord.Member): chan_rules = client.get_channel(CHAN_RULES) embed = build_embed( title="Welcome to the server!", description="The official Husker football discord server", thumbnail= "https://cdn.discordapp.com/icons/440632686185414677/a_061e9e57e43a5803e1d399c55f1ad1a4.gif", fields=[ [ "Rules", f"Please be sure to check out {chan_rules.mention if chan_rules is not None else 'the rules channel'} to catch up on server rules.", ], [ "Commands", f"View the list of commands with the `/commands` command. Note: commands only work while in the server.", ], [ "Roles", "You can assign yourself come flair by using the `/roles` command.", ], ], ) await who.send(embed=embed)
async def send_tweet_alert(message: str): log(f"Receiving Twitter alert", 0) log(f"Twitter Alert: {message}", 1) chan_twitter: discord.TextChannel = client.get_channel( id=CHAN_TWITTERVERSE) embed = build_embed(fields=[["Twitter Stream Listener Alert", message]]) await chan_twitter.send(embed=embed)
async def on_component(self, ctx: ComponentContext): try: # Avoid listening to events that don't apply to the vote command if "Q:" not in ctx.origin_message.embeds[0].title: return except: return embed = ctx.origin_message.embeds[0] voters = embed.fields[2].value voter_name = ctx.author.mention key = embed.footer.text if key not in ctx.component_id: # Avoid over writing other votes return if voter_name in voters: await ctx.send("You cannot vote more than once!", hidden=True) return query = embed.title.split(": ")[1] up_vote_count = int(embed.fields[0].value) up_vote_label = ctx.origin_message.components[0]["components"][0]["label"] down_vote_count = int(embed.fields[1].value) down_vote_label = ctx.origin_message.components[0]["components"][1]["label"] if voters == "_": voters = voter_name else: voters += f", {voter_name}" if ctx.component_id == f"{key}_a": try: up_vote_count += 1 except KeyError: raise CommandError(f"Error modifying [{up_vote_label}]") elif ctx.component_id == f"{key}_b": try: down_vote_count += 1 except KeyError: raise CommandError(f"Error modifying [{down_vote_label}]") embed = build_embed( title=f"Q: {query.capitalize()}", description="Times out after 60 seconds.", inline=False, fields=[ [up_vote_label, str(up_vote_count)], [down_vote_label, str(down_vote_count)], ["Voters", voters], ], footer=key, ) new_buttons = ctx.origin_message.components[0]["components"] await ctx.edit_origin( content="", embed=embed, components=[create_actionrow(*new_buttons)] )
async def _urbandictionary(self, ctx: SlashContext, *, word: str): r = requests.get(f"http://www.urbandictionary.com/define.php?term={word}") soup = BeautifulSoup(r.content, features="html.parser") try: definitions = soup.find_all(name="div", attrs={"class": "def-panel"}) except AttributeError: raise UserError(f"Unable to find [{word}] in the Urban Dictionary.") del r, soup if len(definitions) == 0: raise UserError(f"Unable to find [{word}] in the Urban Dictionary.") try: del definitions[1] # Word of the day except IndexError: pass results = [] for definition in definitions: results.append( self.Definition( lookup_word=definition.contents[1].contents[0].text, meaning=definition.contents[2].text, example=definition.contents[3].text, contributor=definition.contents[4].text, ) ) pages = [] for index, result in enumerate(results): pages.append( build_embed( title=f"Searched for: {result.lookup_word}", description=f"Definition #{index + 1} from Urban Dictionary", fields=[ ["Meaning", result.meaning], ["Example", result.example], ["Contributor", result.contributor], ], ) ) await Paginator( bot=ctx.bot, ctx=ctx, pages=pages, useIndexButton=True, useSelect=False, firstStyle=ButtonStyle.gray, nextStyle=ButtonStyle.gray, prevStyle=ButtonStyle.gray, lastStyle=ButtonStyle.gray, indexStyle=ButtonStyle.gray, ).run()
async def send_reminder( num_seconds, destination: typing.Union[discord.Member, discord.TextChannel], message: str, source: typing.Union[discord.Member, discord.TextChannel], alert_when, missed=False, ): log( f"Starting thread for [{pretty_time_delta(num_seconds)}] seconds. Send_When == [{alert_when}].", 1, ) if not missed: log(f"Destination: [{destination}]", 1) log(f"Message: [{message[:15] + '...'}]", 1) await asyncio.sleep(num_seconds) embed = build_embed( title="Bot Frost Reminder", inline=False, fields=[["Author", source.mention], [f"Reminder!", message]], ) else: embed = build_embed( title="Missed Bot Frost Reminder", inline=False, fields=[ ["Original Reminder Date Time", alert_when], ["Author", source], ["Message", message], ], ) await destination.send(embed=embed) Process_MySQL( sqlUpdateTasks, values=(0, str(destination.id), message, alert_when, str(source)), ) log(f"Thread completed successfully!", 0)
async def on_ready(): threshold = int(len(client.users) * client_percent) log(f"Bot Frost version 3.0", 0) log(f"Name: {client.user}", 1) log(f"ID: {client.user.id}", 1) log(f"Guild: {current_guild()}", 1) log(f"HOF/HOS Reaction Threshold: {threshold}", 1) log(f"The bot is ready!", 0) if "Windows" not in platform.platform(): try: changelog_path = None if "Windows" in platform.platform(): log(f"Windows changelog", 1) changelog_path = pathlib.PurePath( f"{pathlib.Path(__file__).parent.resolve()}/changelog.md") elif "Linux" in platform.platform(): log(f"Linux changelog", 0) changelog_path = pathlib.PurePosixPath( f"{pathlib.Path(__file__).parent.resolve()}/changelog.md") changelog = open(changelog_path, "r") lines = changelog.readlines() lines_str = "" for line in lines: lines_str += f"* {str(line)}" except OSError: lines_str = "Error loading changelog." bot_spam = client.get_channel(CHAN_SCOTTS_BOTS) embed = build_embed( title="Husker Discord Bot", fields=[ [ "Info", f"I was restarted, but now I'm back! I'm now online as {client.user.mention}! Check out /commands.", ], ["HOF/HOS Reaction Threshold", f"{threshold}"], ["Changelog", lines_str], [ "More Changelog", f"[View rest of commits](https://github.com/refekt/Bot-Frost/commits/master)", ], ], ) await bot_spam.send(embed=embed) await change_my_status() await load_tasks()
def ud_embed(embed_word, embed_meaning, embed_example, embed_contributor): return build_embed( title="Urban Dictionary Result", inline=False, footer=embed_contributor, fields=[ [embed_word, embed_meaning], ["Example", embed_example], [ "Link", f"https://www.urbandictionary.com/define.php?term={parse.quote(string=embed_word)}", ], ], )
async def _vote( self, ctx: SlashContext, query: str, option_a: str = "UP VOTE", option_b: str = "DOWN VOTE", ): if (option_a is not None and option_b is None) or ( option_b is not None and option_a is None ): raise UserError("You must provide both options!") option_a = str(option_a).upper() option_b = str(option_b).upper() but_a = ButtonStyle.green but_b = ButtonStyle.red key = set_component_key() buttons_voting = [] query = query.capitalize() if not query.endswith("?"): query += "?" if option_a != "UP VOTE" and option_b != "DOWN VOTE": # Non-standard vote but_a = but_b = ButtonStyle.gray buttons_voting.append( create_button(custom_id=f"{key}_a", label=option_a, style=but_a) ) buttons_voting.append( create_button(custom_id=f"{key}_b", label=option_b, style=but_b) ) embed = build_embed( title=f"Q: {query}", inline=False, fields=[ [buttons_voting[-2]["label"], "0"], [buttons_voting[-1]["label"], "0"], ["Voters", "_"], ], footer=key, ) await ctx.send( content="", embed=embed, components=[create_actionrow(*buttons_voting)] )
async def _teamstats(self, ctx: SlashContext, team_name: str): await ctx.defer() team = TeamStatsWinsipediaTeam(team_name=team_name) embed = build_embed( title=f"{team_name.title()} Historical Stats", fields=[ [ "All Time Record", f"{team.all_time_record} ({team.all_time_record_rank})", ], [ "All Time Wins", f"{team.all_time_wins} ({team.all_time_wins_rank})" ], ["Bowl Games", f"{team.bowl_games} ({team.bowl_games_rank})"], [ "Bowl Record", f"{team.bowl_record} ({team.bowl_record_rank})" ], [ "Championships", f"{team.championships} ({team.championships_rank})" ], [ "Conference Championships", f"{team.conf_championships} ({team.conf_championships_rank})", ], [ "Consensus All American", f"{team.conf_championships} ({team.conf_championships_rank})", ], [ "Heisman Winners", f"{team.heisman_winners} ({team.heisman_winners_rank})", ], [ "NFL Draft Picks", f"{team.nfl_draft_picks} ({team.nfl_draft_picks_rank})", ], [ "Weeks in AP Poll", f"{team.week_in_ap_poll} ({team.week_in_ap_poll_rank})", ], ], inline=False, ) await ctx.send(embed=embed)
async def _crootbot(self, ctx: SlashContext, year: int, search_name: str): print(f"[{datetime.datetime.now().astimezone(tz=TZ)}] ### Crootbot") if len(search_name) == 0: raise UserError("A player's first and/or last search_name is required.") if len(str(year)) == 2: year += 2000 elif len(str(year)) == 1 or len(str(year)) == 3: raise UserError("The search year must be two or four digits long.") if year > datetime.datetime.now().year + 5: raise UserError( "The search year must be within five years of the current class." ) if year < 1869: raise UserError( "The search year must be after the first season of college football--1869." ) await ctx.defer() # Similar to sending a message with a loading screen to edit later on log(f"Searching for [{year} {search_name.capitalize()}]", 1) global croot_search croot_search = FootballRecruit(year, search_name) log(f"Found [{len(croot_search)}] results", 1) if len(croot_search) == 1: return await final_send_embed_fap_loop( ctx=ctx, target_recruit=croot_search[0], bot=self.bot ) result_info = search_result_info(croot_search) action_row = create_actionrow(*search_buttons) embed = build_embed( title=f"Search Results for [{year} {search_name.capitalize()}]", fields=[["Search Results", result_info]], ) await ctx.send(embed=embed, components=[action_row]) log(f"Sent search results for [{year} {search_name.capitalize()}]", 1)
async def _possumdroppings(self, ctx: SlashContext, message: str): await ctx.defer() if not ctx.channel_id == CHAN_POSSUMS: raise UserError( f"You can only use this command in [{ctx.guild.get_channel(CHAN_POSSUMS).mention}]" ) await ctx.send("Thinking...", delete_after=0) embed = build_embed( title="Possum Droppings", inline=False, thumbnail="https://cdn.discordapp.com/attachments/593984711706279937/875162041818693632/unknown.jpeg", footer="Created by a possum", fields=[["Droppings", message]], ) await ctx.send(embed=embed)
async def _compare(self, ctx: SlashContext, comparison_team: str, comparison_against: str): await ctx.defer() comparison_team = comparison_team.replace(" ", "-") comparison_against = comparison_against.replace(" ", "-") comparison = CompareWinsipedia(compare=comparison_team, against=comparison_against) embed = build_embed( title= f"Historical records for [{comparison_team.title()}] vs. [{comparison_against.title()}]", inline=False, fields=[ [ "Links", f"[All Games ]({comparison.full_games_url}) | " f"[{comparison_team.title()}'s Games]({'http://www.winsipedia.com/' + comparison_team.lower()}) | " f"[{comparison_against.title()}'s Games]({'http://www.winsipedia.com/' + comparison_against.lower()})", ], [ f"{comparison_team.title()}'s Recoard vs. {comparison_against.title()}", comparison.all_time_record, ], [ f"{comparison_team.title()}'s Largest MOV", f"{comparison.compare.largest_mov} ({comparison.compare.largest_mov_date})", ], [ f"{comparison_team.title()}'s Longest Win Streak", f"{comparison.compare.longest_win_streak} ({comparison.compare.largest_win_streak_date})", ], [ f"{comparison_against.title()}'s Largest MOV", f"{comparison.against.largest_mov} ({comparison.against.largest_mov_date})", ], [ f"{comparison_against.title()}'s Longest Win Streak", f"{comparison.against.longest_win_streak} ({comparison.against.largest_win_streak_date})", ], ], ) await ctx.send(embed=embed)
async def _eightball(self, ctx: SlashContext, question: str): eight_ball = [ "As I see it, yes.", "Ask again later.", "Better not tell you now.", "Cannot predict now.", "Coach V's cigar would like this!", "Concentrate and ask again.", "Definitely yes!", "Don’t count on it...", "Frosty!", "F**k Iowa!", "It is certain.", "It is decidedly so.", "Most likely...", "My reply is no.", "My sources say no.", "Outlook not so good and reply hazy", "Scott Frost approves!", "These are the affirmative answers.", "Try again...", "Without a doubt.", "Yes – definitely!", "You may rely on it.", ] random.shuffle(eight_ball) embed = build_embed( title="BotFrost Magic 8-Ball :8ball: says...", description="These are all 100% accurate. No exceptions! Unless an answer says anyone other than Nebraska is good.", inline=False, fields=[ ["Question", question.capitalize()], ["Response", random.choice(eight_ball)], ], thumbnail="https://i.imgur.com/L5Gpu0z.png", ) await ctx.send(embed=embed)
async def _lines( self, ctx: SlashContext, week: int = None, team_name: str = "Nebraska", year: int = datetime.now().year, ): log(f"Gathering info for lines", 0) games, stats = HuskerSchedule(sport="football", year=year) del stats lines = None if week is None: week = get_current_week(year=year, team=team_name) week += 1 # account for week 0 log(f"Current week: {week}", 1) icon = None for game in games: if game.week == week: lines = get_consensus_line(team_name=team_name, year=year, week=week - 1) icon = game.icon break if lines is None: lines = "TBD" embed = build_embed( title=f"Betting lines for [{team_name.title()}]", fields=[["Year", year], ["Week", week - 1], ["Lines", lines]], thumbnail=icon, ) await ctx.send(embed=embed) log(f"Lines completed", 0)
async def _police(self, ctx: SlashContext, arestee: discord.Member): message = ( f"**" f"🚨 NANI 🚨\n" f"..🚨 THE 🚨\n" f"...🚨 F**K 🚨\n" f"....🚨 DID 🚨\n" f".....🚨 YOU 🚨\n" f"....🚨 JUST 🚨\n" f"...🚨 SAY 🚨\n" f"..🚨 {arestee.mention} 🚨\n" f"🏃♀️💨 🔫🚓🔫🚓🔫🚓\n" f"\n" f"👮📢 Information ℹ provided in the VIP 👑 Room 🏆 is intended for Husker247 🌽🎈 members only ‼🔫. Please do not copy ✏ and paste 🖨 or summarize this content elsewhere‼ Please try to keep all replies in this thread 🧵 for Husker247 members only! 🚫 ⛔ 👎 " f"🙅♀️Thanks for your cooperation. 😍🤩😘" f"**" ) embed = build_embed( title="Wee woo wee woo!", inline=False, fields=[["Halt!", message]] ) await ctx.send(embed=embed)
async def _fap_predict(self, ctx: SlashContext, year: int, search_name: str): if len(str(year)) == 2: year += 2000 if year > datetime.datetime.now().year + 5: raise UserError( "The search year must be within five years of the current class." ) if year < 1869: raise UserError( "The search year must be after the first season of college football--1869." ) await ctx.defer(hidden=True) global fap_search fap_search = FootballRecruit(year, search_name) if type(fap_search) == commands.UserInputError: return await ctx.send(content=fap_search, hidden=True) async def send_fap_convo(target_recruit): await initiate_fap( ctx=ctx, user=ctx.author, recruit=target_recruit, client=ctx.bot ) if len(fap_search) == 1: return await send_fap_convo(fap_search[0]) result_info = search_result_info(fap_search) action_row = create_actionrow(*search_buttons) embed = build_embed( title=f"Search Results for [{year} {search_name.capitalize()}]", fields=[["Search Results", result_info]], ) await ctx.send(embed=embed, components=[action_row], hidden=True)
async def _remindme( self, ctx: SlashContext, remind_when: str, message: str, who: discord.member = None, channel: discord.TextChannel = None, ): if who and channel: raise UserError( "You cannot input both a member and channel to remind.") elif who and not ctx.author == who: raise UserError( "You cannot set reminders for anyone other than yourself!") elif channel in CHAN_BANNED: raise ValueError( f"Setting reminders in {channel.mention} is banned!") await ctx.defer() today = datetime.today() def convert_dt_value(dt_item: str, from_when: str): if dt_item in from_when: raw = from_when.split(dt_item)[0] if raw.isnumeric(): return int(raw) else: try: findall = re.findall(r"\D", raw)[-1] return int(raw[raw.find(findall) + 1:]) except: return 0 else: return 0 days = convert_dt_value(DateTimeStrings.day, remind_when) hours = convert_dt_value(DateTimeStrings.hour, remind_when) minutes = convert_dt_value(DateTimeStrings.minute, remind_when) seconds = convert_dt_value(DateTimeStrings.seconds, remind_when) time_diff = timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds) min_timer_allowed = 5 # 60 * 5 if time_diff.total_seconds() < min_timer_allowed: raise UserError( f"The num_seconds entered is too short! The minimum allowed timer is {min_timer_allowed} seconds." ) try: raw_when = today + time_diff except ValueError: raise UserError("The num_seconds entered is too large!") duration = raw_when - today send_when = today + duration mysql_author = f"{ctx.author.name}#{ctx.author.discriminator}" is_open = 1 if who: destination = who elif channel: destination = channel else: destination = ctx.channel try: Process_MySQL( sqlRecordTasks, values=( str(destination.id), message, str(send_when), is_open, mysql_author, ), ) destination = ctx.channel except: raise CommandError("Error submitting MySQL") nest_asyncio.apply() asyncio.create_task( send_reminder( num_seconds=duration.total_seconds(), destination=destination, message=message, source=ctx.author, alert_when=str(send_when), )) embed = build_embed( title="Bot Frost Reminders", description= f"Setting a timer for [{destination.mention}] in [{pretty_time_delta(duration.total_seconds())}]. The timer will go off at [{send_when.strftime('%x %X')}].", inline=False, fields=[["Author", ctx.author.mention], ["Message", message]], ) await ctx.send(embed=embed)
async def hall_of_fame_messages(reactions: list): multiple_threshold = False for reaction in reactions: if ( multiple_threshold ): # Rare instance where a message has multiple reactions that break the threshold break if reaction.message.channel.id in ( CHAN_HOF_PROD, CHAN_SHAME, ): # Stay out of HOF and HOS continue slowpoke_emoji = "<:slowpoke:758361250048245770>" server_member_count = len(client.users) reaction_threshold = int(client_percent * server_member_count) hos_channel = hof_channel = None if reaction.count >= reaction_threshold: multiple_threshold = True log( f"Reaction threshold broken with [{reaction.count}] [{reaction.emoji}] in [{reaction.message.channel}] reactions", 0, ) if str(reaction.emoji) == slowpoke_emoji: hof = False hos_channel = client.get_channel(id=CHAN_SHAME) raw_message_history = await hos_channel.history(limit=5000 ).flatten() else: hof = True hof_channel = client.get_channel(id=CHAN_HOF_PROD) raw_message_history = await hof_channel.history(limit=5000 ).flatten() duplicate = False for raw_message in raw_message_history: if len(raw_message.embeds) > 0: if str(reaction.message.id ) in raw_message.embeds[0].footer.text: duplicate = True break del raw_message_history if not duplicate: slowking_path = None if not hof: embed_title = f"{slowpoke_emoji * 3} Hall of Shame Message {slowpoke_emoji * 3}" embed_description = ( "Messages so shameful they had to be memorialized forever!" ) channel = hos_channel avatar_url = (str( reaction.message.author.avatar_url).split("?") [0].replace("webp", "png")) make_slowking(avatar_url) slowking_path = f"{pathlib.Path(__file__).parent.resolve()}\\resources\\images\\new_slowking.png" slowking_path = upload_picture(slowking_path) else: embed_title = f"{'🏆' * 3} Hall of Fame Message {'🏆' * 3}" embed_description = ( "Messages so amazing they had to be memorialized forever!" ) channel = hof_channel embed = build_embed( title=embed_title, description=embed_description, thumbnail=slowking_path if not None else None, fields=[ ["Author", reaction.message.author.mention], ["Message", reaction.message.content], [ "Message Link", f"[Click to view message]({reaction.message.jump_url})", ], ], footer= f"Message ID: {reaction.message.id} | Hall of Shame message created at {reaction.message.created_at.strftime('%B %d, %Y at %H:%M%p')}", ) await channel.send(embed=embed) log(f"Processed HOF/HOS message.", 0)
async def send_tweet(tweet): if tweet.author.id_str not in [ member["id_str"] for member in list_members ]: return direct_url = ( f"https://twitter.com/{tweet.author.screen_name}/status/{tweet.id_str}/" ) if hasattr(tweet, "extended_tweet"): fields = [["Message", tweet.extended_tweet["full_text"]]] else: fields = [["Message", tweet.text]] embed = build_embed( url="https://twitter.com/i/lists/1307680291285278720", fields=fields, footer=f"Tweet sent {tweet.created_at.strftime(DT_TWEET_FORMAT)}", ) embed.set_author( name= f"{tweet.author.name} (@{tweet.author.screen_name}) via {tweet.source}", icon_url=tweet.author.profile_image_url_https, ) if hasattr(tweet, "extended_entities"): try: for index, media in enumerate(tweet.extended_entities["media"]): if index == 0: embed.set_image(url=tweet.extended_entities["media"][index] ["media_url"]) embed.add_field( name=f"Media #{index + 1}", value=f"[Link #{index + 1}]({media['media_url']})", inline=False, ) except: pass log(f"Sending tweeit from @{tweet.author.screen_name}", 1) chan_twitter: discord.TextChannel = client.get_channel( id=CHAN_TWITTERVERSE) buttons = [ create_button( style=ButtonStyle.gray, custom_id=f"{set_component_key()}_send_to_general", label="Send to General", ), create_button( style=ButtonStyle.gray, custom_id=f"{set_component_key()}_send_to_recruiting", label="Send to Recruiting", ), create_button(style=ButtonStyle.URL, label="Open Tweet", url=direct_url), ] actionrow = create_actionrow(*buttons) # noinspection PyArgumentList await chan_twitter.send(embed=embed, components=[actionrow])
async def _weather( self, ctx: SlashContext, city: str, state: str, country: str = "US" ): def shift_utc_tz(dt, shift): return dt + timedelta(seconds=shift) if not len(state) == 2: raise UserError("State input must be the two-digit state code.") found = False for item in US_STATES: if item.get("Code") == state.upper(): found = True break if not found: raise UserError( f"Unable to find the state {state.upper()}. Please try again!" ) weather_url = f"https://api.openweathermap.org/data/2.5/weather?appid={WEATHER_API_KEY}&units=imperial&lang=en&q={city},{state},{country}" response = requests.get(weather_url, headers=HEADERS) j = json.loads(response.content) weather = WeatherResponse(j) if weather.cod == "404": raise UserError( f"Unable to find {city.title()}, {state.upper()}. Try again!" ) temp_str = ( f"Temperature: {weather.main.temp}℉\n" f"Feels Like: {weather.main.feels_like}℉\n" f"Humidity: {weather.main.humidity}%\n" f"Max: {weather.main.temp_max}℉\n" f"Min: {weather.main.temp_min}℉" ) if len(weather.wind) == 2: wind_str = ( f"Speed: {weather.wind.speed} MPH\n" f"Direction: {weather.wind.deg} °" ) elif len(weather.wind) == 3: wind_str = ( f"Speed: {weather.wind.speed} MPH\n" f"Gusts: {weather.wind.gust} MPH\n" f"Direction: {weather.wind.deg} °" ) else: wind_str = f"Speed: {weather.wind.speed} MPH" hourly_url = f"https://api.openweathermap.org/data/2.5/onecall?lat={weather.coord.lat}&lon={weather.coord.lon}&appid={WEATHER_API_KEY}&units=imperial" response = requests.get(hourly_url, headers=HEADERS) j = json.loads(response.content) hours = [] for index, item in enumerate(j["hourly"]): hours.append(WeatherHour(item)) if index == 3: break hour_temp_str = "" hour_wind_str = "" for index, hour in enumerate(hours): if index < len(hours) - 1: hour_temp_str += f"{hour.temp}℉ » " hour_wind_str += f"{hour.wind_speed} MPH » " else: hour_temp_str += f"{hour.temp}℉" hour_wind_str += f"{hour.wind_speed} MPH" sunrise = shift_utc_tz(weather.sys.sunrise, weather.timezone) sunset = shift_utc_tz(weather.sys.sunset, weather.timezone) sun_str = ( f"Sunrise: {sunrise.astimezone(tz=TZ).strftime(DT_OPENWEATHER_UTC)}\n" f"Sunset: {sunset.astimezone(tz=TZ).strftime(DT_OPENWEATHER_UTC)}" ) embed = build_embed( title=f"Weather conditions for {city.title()}, {state.upper()}", description=f"It is currently {weather.weather[0].main} with {weather.weather[0].description}. {city.title()}, {state.upper()} is located at {weather.coord.lat}, {weather.coord.lon}.", fields=[ ["Temperature", temp_str], ["Clouds", f"Coverage: {weather.clouds.all}%"], ["Wind", wind_str], ["Temp Next 4 Hours", hour_temp_str], ["Wind Next 4 Hours", hour_wind_str], ["Sun", sun_str], ], inline=False, thumbnail=f"https://openweathermap.org/img/wn/{weather.weather[0].icon}@4x.png", ) await ctx.send(embed=embed)
async def _seasonstats( self, ctx: SlashContext, team_name: str = "Nebraska", year: int = datetime.now().year, ): cfb_api = StatsApi(ApiClient(cfbd_config)) try: api_response = cfb_api.get_team_season_stats_with_http_info( year=year, team=team_name) except ApiException: return None season_stats = {} for stat in api_response[0]: season_stats[stat.stat_name] = stat.stat_value pages = [ # Offense build_embed(fields=[ [ "Offense", f"**Total Yards**: {season_stats.get('totalYards', 0):,}\n" f"---\n" f"**Rushing Attempts**: {season_stats.get('rushingAttempts', 0):,}\n" f"**Rushing Yards**: {season_stats.get('rushingYards', 0):,}\n" f"**Rushing TDs**: {season_stats.get('rushingTDs', 0)}\n" f"---\n" f"**Pass Attempts**: {season_stats.get('passAttempts', 0):,}\n" f"**Pass Completions**: {season_stats.get('passCompletions', 0):,}\n" f"**Passing Yards**: {season_stats.get('netPassingYards', 0):,}\n" f"**Passing TDs**: {season_stats.get('passingTDs', 0)}\n" f"---\n" f"**First Downs**: {season_stats.get('firstDowns', 0):,}\n" f"**Third Downs**: {season_stats.get('thirdDowns', 0):,}\n" f"**Third Down Conversions**: {season_stats.get('thirdDownConversions', 0):,}\n" f"**Fourth Downs**: {season_stats.get('fourthDowns', 0)}\n" f"**Fourth Down Conversions**: {season_stats.get('fourthDownConversions', 0)}\n" f"---\n" f"**Interceptions Thrown**: {season_stats.get('interceptions', 0)}\n" f"---\n" f"**Time of Possession**: {pretty_time_delta(season_stats.get('possessionTime', 0))}\n", ], ], ), # Defense build_embed(fields=[ [ "Defense", f"**Tackles for Loss**: {season_stats.get('tacklesForLoss', 0)}\n" f"**Sacks**: {season_stats.get('sacks', 0)}\n" f"**Passes Intercepted**: {season_stats.get('passesIntercepted', 0)}\n" f"**Interception Yards**: {season_stats.get('interceptionYards', 0)}\n" f"**Interception TDs**: {season_stats.get('interceptionTDs', 0)}\n", ], ], ), # Special Teams build_embed(fields=[ [ "Special Teams", f"**Kick Returns**: {season_stats.get('kickReturns', 0)}\n" f"**Kick Return Yards**: {season_stats.get('kickReturnYards', 0):,}\n" f"**Kick Return TDs**: {season_stats.get('kickReturnTDs', 0)}\n" f"---\n" f"**Punt Returns**: {season_stats.get('puntReturns', 0)}\n" f"**Punt Return Yards**: {season_stats.get('puntReturnYards', 0):,}\n" f"**Punt Return TDs**: {season_stats.get('puntReturnTDs', 0)}\n", ], ], ), # Penalties build_embed(fields=[ [ "Penalties", f"**Penalties**: {season_stats.get('penalties', 0)}\n" f"**Penalty Yards**: {season_stats.get('penaltyYards', 0):,}\n", ], ], ), # Fumbles and Turnovers build_embed(fields=[ [ "Fumbles and Turnovers", f"**Fumbles Lost**: {season_stats.get('fumblesLost', 0)}\n" f"**Fumbles Recovered**: {season_stats.get('fumblesRecovered', 0)}\n" f"**Turnovers**: {season_stats.get('turnovers', 0)}\n", ], ], ), ] content = [ f"{team_name.title()}'s {year} Offensive Stats", f"{team_name.title()}'s {year} Defensive Stats", f"{team_name.title()}'s {year} Special Teams Stats", f"{team_name.title()}'s {year} Penalties Stats", f"{team_name.title()}'s {year} Fumble and Turnover Stats", ] await Paginator( bot=ctx.bot, ctx=ctx, pages=pages, content=content, useIndexButton=True, useSelect=False, firstStyle=ButtonStyle.gray, nextStyle=ButtonStyle.gray, prevStyle=ButtonStyle.gray, lastStyle=ButtonStyle.gray, indexStyle=ButtonStyle.gray, ).run()
async def predict(self, ctx, year: int, *name): """Put in a FAP prediction for a recruit.""" from utilities.embed import build_embed if len(name) == 0: raise discord.ext.commands.UserInputError( "A player's first and/or last name is required." ) if len(str(year)) == 2: year += 2000 if year > datetime.datetime.now().year + 5: raise discord.ext.commands.UserInputError( "The search year must be within five years of the current class." ) if year < 1869: raise discord.ext.commands.UserInputError( "The search year must be after the first season of college football--1869." ) edit_msg = await ctx.send("Loading...") search = FootballRecruit(year, name) if type(search) == commands.UserInputError: await edit_msg.edit(content=search) return async def send_fap_convo(target_recruit): await initiate_fap(ctx.message.author, target_recruit, self.bot) if len(search) == 1: await edit_msg.delete() await send_fap_convo(search[0]) return result_info = "" search_reactions = { "1️⃣": 0, "2️⃣": 1, "3️⃣": 2, "4️⃣": 3, "5️⃣": 4, "6️⃣": 5, "7️⃣": 6, "8️⃣": 7, "9️⃣": 8, "🔟": 9, } index = 0 for index, result in enumerate(search): if index < 10: result_info += f"{list(search_reactions.keys())[index]}: {result.year} - {'⭐' * result.rating_stars}{' - ' + result.position if result.rating_stars > 0 else result.position} - {result.name}\n" embed = build_embed( title=f"Search Results for [{year} {[n for n in name]}]", fields=[["Search Results", result_info]], ) await edit_msg.edit(content="", embed=embed) for reaction in list(search_reactions.keys())[0 : index + 1]: await edit_msg.add_reaction(reaction) def checking_reaction(reaction, user): if not user.bot: return (reaction.emoji in search_reactions) and ( user == ctx.message.author ) search_result_player = None try: reaction, user = await self.bot.wait_for( "reaction_add", check=checking_reaction ) except asyncio.TimeoutError: pass else: search_result_player = search[search_reactions[reaction.emoji]] try: await edit_msg.delete() except discord.HTTPException: log(f"Deleting the message failed.", 1) except discord.ClientException: log(f"Unable to delete message due to lack of permissions.", 1) await send_fap_convo(search_result_player)