async def p_view(message: discord.Message, prefix: str): """ Views a saved poll. :param message: A discord.Message object. :param prefix: The server's prefix. """ dat = _read(f""" SELECT * FROM old_polls WHERE server="{message.server.id}" AND topic_index="{message.content.replace(f"p{prefix}view ", "")}"; """.replace("\t", "")) embed_obj = Embed( title=dat[0][2], description=f"Poll status for poll [{dat[0][1]}].", colour=Colour.dark_purple()) for item in dat: embed_obj.add_field(name=f"{item[4]} ({item[3]})", value=str(item[5])) _sum = 0 for item in dat: _sum += item[5] if _sum is None: _sum = "No" else: _sum = parse_num(_sum) word = 'votes' if not _sum == '1' else 'vote' embed_obj.set_footer(text=f"{_sum} {word}...") await CLIENT.send_message(message.channel, "Poll status... :clipboard:", embed=embed_obj) del dat del embed_obj del _sum del word
async def _generate_embed(self, exercise: Exercise, is_reminder=False) -> Embed: title = (f'Abgabe in 1h: {exercise.title}' if is_reminder else f'Neue Aufgabe: {exercise.title}') embed = Embed( title=title, type='rich', colour=Colour.orange() if is_reminder else Colour.dark_purple(), url=exercise.url, ) embed.set_author(name=exercise.author) if len(exercise.message) > 1022: exercise.message = exercise.message[1018:] + '*...*' embed.add_field( name='Nachricht', value=exercise.message, ) embed.add_field( name='Abgabetermin', value=exercise.end_date.strftime(self.datetime_format), ) embed.set_footer(text=self.bot.signature) return embed
def generate_signups_embed(bot, signups, event): embed = Embed(title=f"Signups - {event.title}", colour=Colour.dark_purple()) playing_signups = [] sub_signups = [] unregistered_signups = [signup for signup in signups if not Player.exists_discord_id(signup.user_id)] for signup in signups: if signup.can_play: playing_signups.append(signup) if signup.can_sub: sub_signups.append(signup) signups_tag_str = "" subs_tag_str = "" if len(playing_signups) > 0: for signup in playing_signups: user = bot.get_user(signup.user_id) player = Player.exists_discord_id(signup.user_id) signups_tag_str += f"@{user} ({player.minecraft_username if player else 'Unregistered'})\n" else: signups_tag_str = "Nobody :(" if len(sub_signups) > 0: for signup in sub_signups: user = bot.get_user(signup.user_id) subs_tag_str += f"@{user} \n" else: subs_tag_str = "Nobody :(" embed.add_field(name="Signed", value=f"```{signups_tag_str}```", inline=False) embed.add_field(name="Can Sub", value=f"```{subs_tag_str}```", inline=False) if unregistered_signups: tags = "\n".join([f"@{bot.get_user(signup.user_id)} " for signup in unregistered_signups]) embed.add_field(name="Unregistered:", value=f"```{tags}```", inline=False) return embed
async def rosters_comparison(self, old_threads, new_threads): #Compares old and new forum threads (team sizes) changes = "" #TODO: Handle error for when teams change their threads titles old_links = {old_threads[old_key]["link"]: old_key for old_key in old_threads.keys()} new_links = {new_threads[new_key]["link"]: new_key for new_key in new_threads.keys()} disjunct_union = set(old_links.keys()) ^ set(new_links.keys()) for disjunct in disjunct_union: if disjunct in old_links: changes += f"🔴 **{old_links[disjunct]}** has disbanded.\n\n" else: changes += f"🟢 **{new_links[disjunct]}** is now official.\n\n" for o_key in old_threads.keys(): for n_key in new_threads.keys(): if o_key != n_key: continue if new_threads[n_key]['members'] != old_threads[o_key]['members']: new_size = int(new_threads[n_key]['members'].split("/")[0]) old_size = int(old_threads[o_key]['members'].split("/")[0]) if new_size > old_size: changes += ( f"🟢 **{o_key}:** {old_threads[o_key]['members']} -> {new_threads[n_key]['members']} (**+{new_size - old_size}**)\n\n") else: changes += ( f"🔴 **{n_key}:** {old_threads[o_key]['members']} -> {new_threads[n_key]['members']} (**{new_size - old_size}**)\n\n") if changes: embed = Embed(title="Roster Changes", description=changes, color=Colour.dark_purple()) message = await self.general_chat.send(embed=embed) return message else: print(f"No roster moves in the last {FORUM_THREADS_INTERVAL_HOURS}h")
async def check_stream(self): token = os.environ.get('TWITCH_TOKEN') client_id = cfg['TWITCH_CLIENT_ID'] user_id = cfg['TWITCH_USER_ID'] if token is None: raise RuntimeError( 'TWITCH_TOKEN is not set in environment variables.') auth = 'Bearer ' + token headers = { 'Authorization': auth, 'Client-ID': client_id, } url = 'https://api.twitch.tv/helix/streams?user_id=' + str(user_id) async with aiohttp.ClientSession() as session: twitch_response = await self.fetch_json(session, url, headers) channel_id = cfg['DEFAULT_ANNOUNCE_CHANNEL'] channel = self.bot.get_channel(channel_id) last_stream = (datetime.now() - self.last_time).total_seconds() / 3600.0 if len(twitch_response['data']) > 0 and (last_stream > 3.0 or self.stopped): title = twitch_response['data'][0]['title'] thumbnail = twitch_response['data'][0]['thumbnail_url'] username = twitch_response['data'][0]['user_name'] description = username + ' acaba de entrar em live!' + '<:batataThinking:731871457470316574>' + '\n https://www.twitch.tv/' + username thumbnail = thumbnail.replace('{width}', '1280') thumbnail = thumbnail.replace('{height}', '720') img = await self.fetch_image(session, thumbnail) with open('twitch_thumbnail.png', 'wb') as f: f.write(img) file = File("twitch_thumbnail.png", filename="image.png") colour = Colour.dark_purple() embed = Embed(title=title, type='rich', colour=colour, description=description) embed = embed.set_image(url="attachment://image.png") await channel.send(file=file, embed=embed) self.last_time = datetime.now() self.stopped = False elif len(twitch_response['data']) == 0: self.stopped = True
async def element_color(element): switch = { 'Light': Colour.gold(), 'Dark': Colour.dark_purple(), 'Fire': Colour.dark_red(), 'Water': Colour.dark_blue(), 'Forest': Colour.dark_green() } return switch.get(element)
async def stats(self, ctx): """ Gets most recent stats from match 1 and 2 """ await ctx.defer() match_1 = get_server_games("1.ctfmatch.brawl.com") match_2 = get_server_games("2.ctfmatch.brawl.com") match_1.reverse() match_2.reverse() with open("utils/maps.json") as file: maps = load(file) embed = Embed(title="Match Stats", color=Colour.dark_purple()) if match_1: embed_1_value = [] index = min(3, len(match_1)) for i in range(index): game = CTFGame(match_1[i]) if game.map_name in maps.keys(): map_str = f":map: **[{game.map_name}](https://www.brawl.com/games/ctf/maps/{maps[game.map_name]})**" else: map_str = f":map: **{game.map_name}**" if game.mvp: mvp_str = f":trophy: **[{game.mvp}](https://www.brawl.com/players/{game.mvp})**" else: mvp_str = f":trophy: **No One :(**" embed_1_value.append(f"{map_str} | {mvp_str}") embed_1_value.append( f":chart_with_upwards_trend: **[Stats](https://www.brawl.com/games/ctf/lookup/{game.game_id})**") embed_1_value.append("") embed.add_field(name="__Match 1__", value="\n".join(embed_1_value), inline=False) if match_2: embed_2_value = [] index = min(3, len(match_2)) for i in range(index): game = CTFGame(match_2[i]) if game.map_name in maps.keys(): map_str = f":map: **[{game.map_name}](https://www.brawl.com/games/ctf/maps/{maps[game.map_name]})**" else: map_str = f":map: **{game.map_name}**" if game.mvp: mvp_str = f":trophy: **[{game.mvp}](https://www.brawl.com/players/{game.mvp})**" else: mvp_str = f":trophy: **No One :(**" embed_2_value.append(f"{map_str} | {mvp_str}") embed_2_value.append( f":chart_with_upwards_trend: **[Stats](https://www.brawl.com/games/ctf/lookup/{game.game_id})**") embed_2_value.append("") embed.add_field(name="__Match 2__", value="\n".join(embed_2_value), inline=False) if not embed.fields: await response_embed(ctx, "No Games Found", "There are no match games in the past 10 games played.") else: await ctx.send(embed=embed)
async def twitch_title_command(self, ctx, username: str): User_URL = f"https://api.twitch.tv/kraken/users?login={username}" async with request( "GET", User_URL, headers={ "Client-ID": os.environ.get("twitchclientid"), "Accept": "application/vnd.twitchtv.v5+json", }, ) as response: if response.status == 200: User_ID = (await response.json())["users"][0]["_id"] StreamInfo_URL = f"https://api.twitch.tv/kraken/streams/{User_ID}" async with request( "GET", StreamInfo_URL, headers={ "Client-ID": os.environ.get("twitchclientid"), "Accept": "application/vnd.twitchtv.v5+json", }, ) as response2: if response2.status == 200: if (await response2.json())["stream"] != None: embed = Embed( title= f"{(await response2.json())['stream']['channel']['display_name']} Stream Info", colour=Colour.dark_purple(), timestamp=datetime.utcnow(), ) fields = [ ( "Title", f"{(await response2.json())['stream']['channel']['status']}", True, ), ( "Game", f"{(await response2.json())['stream']['channel']['game']}", True, ), ] for name, value, inline in fields: embed.add_field(name=name, value=value, inline=inline) embed.set_thumbnail( url=(await response2.json() )["stream"]["channel"]["logo"]) await ctx.reply(embed=embed)
async def nuke_todos(self, ctx): """This will delete the whole todo list of a specific user. Good if user has too many todos.""" if Path( f"{BASE_DIR}/todo_list_data.json" ).is_file(): # Checks file if it exists if ( os.stat(f"{BASE_DIR}/todo_list_data.json").st_size > 0 ): # This will check if the file is NOT empty with open(f"{BASE_DIR}/todo_list_data.json", "r+") as read: todo_file_read = json.load(read) if str(ctx.author.id) in todo_file_read: if todo_file_read[str(ctx.author.id)]: todo_file_read[str(ctx.author.id)] = {} embed_nuked_todos = Embed( title=f"NUKED! :exploding_head:", description=f"Your todo list is now empty {ctx.author}.", color=Colour.dark_purple(), ) with open( f"{BASE_DIR}/todo_list_data.json", "w+" ) as update: json.dump(todo_file_read, fp=update) await ctx.send(embed=embed_nuked_todos) else: await ctx.send( embed=Embed( title="You have no existing entries! Grrrr! Nothing to nuke :exploding_head:!", color=Colour.red(), ) ) else: await ctx.send( embed=Embed( title="You have no existing entries! Grrrr! Nothing to nuke :exploding_head:!", color=Colour.red(), ) ) else: await ctx.send( embed=Embed( title="Todo list file empty! Arf! Nothing to nuke :exploding_head:!", color=Colour.red(), ) ) else: await ctx.send( embed=Embed( title="Todo list file does not exist! Nothing to nuke :exploding_head:", color=Colour.red(), ) )
async def cry(self, ctx: commands.Context): df = self.currency.fetch_crypto() embed = Embed(color=Colour.dark_purple()) embed.title = 'Valor das Criptomoedas' embed.set_author(name='CoinMarketCap', url='https://coinmarketcap.com/pt-br/') for _, name, price in df.itertuples(): embed.add_field(name=name, value=price, inline=False) embed.set_footer(text=str(datetime.now())) await handler.send_message(ctx, logger, embed=embed)
async def coinflip(self, ctx): """ Coinflip """ c = randint(0, 1) if c == 0: result = "**Heads**" else: result = "**Tails**" await ctx.send(embed=Embed(title="Coinflip 🪙", description=f"You flipped {result}", color=Colour.dark_purple()))
async def announce_event(title, description, announcement_channel, signup_list_channel, mention_role, event_time, signup_deadline): embed_description = f"**Time:**\n{event_time[0][1]} (<t:{int(event_time[0][0].timestamp())}:R>)\n\n**Signup Deadline:**\n{signup_deadline}\n\n{description}\n\n" \ f"React with ✅ to play\nReact with 🔇 if you cannot speak\nReact with 🛗 if you are able to sub" embed = Embed(title=title, description=embed_description, color=Colour.dark_purple()) if mention_role.lower() == "none": mention_role = "" announcement_message = await announcement_channel.send(content=f"{mention_role}", embed=embed) embed.set_footer(text=f"Event ID: {announcement_message.id}") embed.description += f"\n[View the event online]({WEB_URL}/event/{announcement_message.id})" await announcement_message.edit(embed=embed) description = f"{title}\n\n**Time:**\n{event_time[0][1]} (<t:{int(event_time[0][0].timestamp())}:R>)\n\n**Signup Deadline:**\n{signup_deadline}\n\n{description}" embed = Embed(title="Signups", description=description, color=Colour.dark_purple()) embed.add_field(name="✅ Players: 0", value="No one :(", inline=False) embed.add_field(name="🛗 Subs: 0", value="No one :(", inline=False) signup_list_message = await signup_list_channel.send(embed=embed) await announcement_message.add_reaction("✅") await announcement_message.add_reaction("🔇") await announcement_message.add_reaction("🛗") await announcement_message.add_reaction("🗺️") # For Mods to react to set up maps return [announcement_message.id, signup_list_message.id]
async def nuke_todos(self, ctx: Context) -> None: """This will delete the whole todo list of a specific user. Good if user has too many todos.""" if TODO_FILE.is_file(): if os.stat(TODO_FILE).st_size > 0: with open(TODO_FILE, "r+") as read: todo_file_read = json.load(read) if str(ctx.author.id) in todo_file_read: if todo_file_read[str(ctx.author.id)]: todo_file_read[str(ctx.author.id)] = {} embed_nuked_todos = Embed( title="NUKED! :exploding_head:", description=f"Your todo list is now empty {ctx.author}.", color=Colour.dark_purple(), ) with open( TODO_FILE, "w+" ) as update: json.dump(todo_file_read, fp=update) await ctx.send(embed=embed_nuked_todos) else: await ctx.send( embed=Embed( title="You have no existing entries! Nothing to nuke :exploding_head:!", color=Colour.red(), ) ) else: await ctx.send( embed=Embed( title="You have no existing entries! Nothing to nuke :exploding_head:!", color=Colour.red(), ) ) else: await ctx.send( embed=Embed( title="Todo list file empty! Arf! Nothing to nuke :exploding_head:!", color=Colour.red(), ) ) else: await ctx.send( embed=Embed( title="Todo list file does not exist! Nothing to nuke :exploding_head:", color=Colour.red(), ) )
async def update_events(self, interval: int = 12): ''' Updates the events channel. :interval (int): The interval in hours to update. ''' bot = self.bot await bot.wait_until_ready() channel = bot.get_channel(bot.events_channel) logging.info(f'update_events being ran on {channel}.') while bot.is_ready(): logging.info('sending an event update.') seconds = interval * 3600 now = datetime.utcnow().replace(tzinfo=pytz.utc) wiki = await gbfwiki.init_wiki() events = wiki.get_events() msg_current = Embed(title='Granblue Fantasy Current Events', url='https://gbf.wiki', color=Colour.teal(), timestamp=now) for event in events['current']: msg_current.add_field( name=f"[{event['title']}]({event['url']})", value=f"Ends on {event['finish']}", inline=False) msg_upcoming = Embed(title='Granblue Fantasy Upcoming Events', url='https://gbf.wiki', color=Colour.dark_purple(), timestamp=now) for event in events['upcoming']: msg_upcoming.add_field( name=f"[{event['title']}]({event['url']})", value=f"{event['start']} to {event['finish']}", inline=False) existing_messages = [] async for message in channel.history(limit=200): # Assume the first message to edit is the current events, # and the second message is the upcoming events. if message.author == bot.user and message.pinned: existing_messages.append(message) if len(existing_messages) >= 2: break await existing_messages[0].edit(embed=msg_current) await existing_messages[1].edit(embed=msg_upcoming) await asyncio.sleep(seconds)
async def rngmap(self, ctx): """ Picks a random map out of a preset map pool """ await ctx.defer() seed() with open("utils/rng_maps.json") as file: maps = load(file) random_map = choice(list(maps.keys())) file = File(f"assets/map_screenshots/{maps[random_map]}.jpg", filename=f"{maps[random_map]}.png") embed = Embed(title="RNG Map", description=f"You will be playing [{random_map}](https://www.brawl.com/games/ctf/maps/" f"{maps[random_map]}) ({maps[random_map]})\n_(Used by {ctx.author.mention})_", color=Colour.dark_purple()) embed.set_image(url=f"attachment://{maps[random_map]}.png") response = await ctx.send("Grabbing a map from the pool") await ctx.channel.send(file=file, embed=embed) await response.delete()
async def p_end(message: discord.Message, prefix: str): """ Ends a vote. :param message: A discord.Message object. :param prefix: The server's prefix. """ content = message.content.replace(f"p{prefix}end ", "") dat = _read(f""" SELECT * FROM polls WHERE server = "{message.server.id}" AND topic_index = "{content}" ORDER BY result DESC; """.replace("\t", "")) embed_obj = Embed( title=dat[0][2], description=f"Poll results for poll {dat[0][1]}.", colour=Colour.dark_purple()) for item in dat: embed_obj.add_field(name=f"{item[4]} ({item[3]})", value=str(item[5])) _sum = 0 for item in dat: _sum += item[5] if _sum is None: _sum = "No" else: _sum = parse_num(_sum) word = "votes" if not _sum == "1" else "vote" embed_obj.set_footer(text=f"{_sum} total {word}.") await CLIENT.send_message(message.channel, "Poll results... :clipboard:", embed=embed_obj) _execute(f""" DELETE FROM polls WHERE server = "{message.server.id}" AND topic_index = "{content}"; """.replace("\t", "")) del content del dat del embed_obj del _sum del word
async def update_usernames(self): server = self.bot_channel.guild changes_list = [] for player in Player.fetch_players_list(): old_username = player.minecraft_username latest_username = player.update_minecraft_username() if latest_username != old_username and latest_username is not None: changes_list.append([player, old_username]) await async_sleep(1) if len(changes_list) > 0: embed = Embed(title="IGNs Updated", color=Colour.dark_purple()) for change in changes_list: player = change[0] member = server.get_member(player.discord_id) old_username = change[1] if not member.nick: member.nick = member.name team_list = re.findall(r"^\[(\w{1,4})\]", member.nick) alias_list = re.findall(r"\s\((.*)\)$", member.nick) new_nick = f"{'[' + team_list[0] + '] ' if team_list else ''}{player.minecraft_username}" + \ (f" ({alias_list[0]})" if alias_list else "") if UPDATE_NICKNAMES: try: await member.edit(nick=new_nick) except Forbidden: embed_value = f"🔴 Failed to update nickname to `{new_nick}` (Forbidden)" else: embed_value = f"Updated server nickname to `{new_nick}`" try: await success_embed( member, f"PUG server nickname updated to `{new_nick}`") embed_value += " (DM sent)" except Forbidden: embed_value += " (confirmation DM failed to send)" else: embed_value = "Nickname updates disabled in config." embed.add_field( name=f"{old_username} → {player.minecraft_username}", value=embed_value, inline=False) await self.bot_channel.send(embed=embed)
async def deposit_notification_message(recipient: User, tx_details: dict): sys_embed = Embed( title=":inbox_tray: __Deposit Processed__ :inbox_tray: ", description=f'Deposit processed successfully!', colour=Colour.dark_purple(), timestamp=datetime.utcnow()) sys_embed.add_field(name=':map: From :map: ', value=f'{tx_details["source_account"]}', inline=False) sys_embed.add_field(name=CONST_HASH_STR, value=f'{tx_details["hash"]}', inline=False) sys_embed.add_field(name=f':gem: Asset :gem: ', value=f'{tx_details["asset_type"]["code"]}') sys_embed.add_field( name=":moneybag: Amount :moneybag: ", value=f"{int(tx_details['asset_type']['amount']) / 10000000:9.7f}", inline=False) await recipient.send(embed=sys_embed)
async def game(self, ctx, keyword=""): """ Toggle some opt-in roles """ user = ctx.message.author keyword = keyword.lower() try: with open("database/roles.json") as f: js = load(f) except FileNotFoundError: js = {} try: rolename = js[keyword]["role"] role = get(ctx.message.guild.roles, name=rolename) if role in user.roles: await user.remove_roles(role) await ctx.send("Left {}".format(rolename)) return await user.add_roles(role) await ctx.send("Joined {}".format(rolename)) except KeyError: if keyword == "": embed = Embed(title="Game List:", colour=Colour.dark_purple()) embed.description = "" for k in js: embed.description += "- {} {}: `{}`\n".format( js[k]["emoji"], js[k]["description"], k ) await ctx.send("", embed=embed) return await ctx.send("This role is not in the database!")
async def profile(self, ctx, user: User = None): """ Displays a user's profile """ if user: if not isinstance(user, int): player_id = user.id else: player_id = user else: player_id = ctx.author.id try: player = Player.from_discord_id(player_id) except PlayerDoesNotExistError: await error_embed(ctx, "Player does not exist") return #Position in leaderboard data = get_sorted_elo() count = 1 for item in data: if player: if player.minecraft_username == item[0]: leader_pos = count break count += 1 stats = f"**ELO:** {getattr(player, 'elo')}\n**Rank**: #{leader_pos}\n**Discord:** <@{getattr(player, 'discord_id')}>" #for key in player.__dict__.keys(): # stats += f"**{key}:** {getattr(player, key)}\n" embed = Embed(description=stats, color=Colour.dark_purple()) embed.set_author( name=f"User profile - {getattr(player, 'minecraft_username')}", icon_url= f"https://cravatar.eu/helmavatar/{getattr(player, 'minecraft_id')}/128.png" ) await ctx.send(embed=embed)
async def twitch_search(self, ctx, username: str): User_URL = f"https://api.twitch.tv/kraken/users?login={username}" async with request( "GET", User_URL, headers={ "Client-ID": os.environ.get("twitchclientid"), "Accept": "application/vnd.twitchtv.v5+json", }, ) as response: if response.status == 200: User_ID = (await response.json())["users"][0]["_id"] StreamInfo_URL = f"https://api.twitch.tv/kraken/streams/{User_ID}" async with request( "GET", StreamInfo_URL, headers={ "Client-ID": os.environ.get("twitchclientid"), "Accept": "application/vnd.twitchtv.v5+json", }, ) as response2: if response2.status == 200: if (await response2.json())["stream"] != None: embed = Embed( title= f"{(await response2.json())['stream']['channel']['display_name']} Stream Info", colour=Colour.dark_purple(), timestamp=datetime.utcnow(), ) fields = [ ( "Name", f"{(await response2.json())['stream']['channel']['display_name']}", False, ), ( "Title", f"{(await response2.json())['stream']['channel']['status']}", True, ), ( "Game", f"{(await response2.json())['stream']['channel']['game']}", True, ), ( "Viewers", f"{(await response2.json())['stream']['viewers']}", True, ), ( "Lagnuage", f"{(await response2.json())['stream']['channel']['broadcaster_language']}", True, ), ( "Followers", f"{(await response2.json())['stream']['channel']['followers']}", True, ), ( "Patner Status", f"{(await response2.json())['stream']['channel']['partner']}", True, ), ( "Went live at:", f"{(await response2.json())['stream']['created_at']}", True, ), ( "URL", (await response2.json() )["stream"]["channel"]["url"], False, ), ] for name, value, inline in fields: embed.add_field(name=name, value=value, inline=inline) embed.set_image( url=(await response2.json() )["stream"]["preview"]["large"]) embed.set_thumbnail( url=(await response2.json() )["stream"]["channel"]["logo"]) await ctx.reply(embed=embed) else: UserInfo_URL = ( f"https://api.twitch.tv/kraken/channels/{User_ID}" ) UserInfo2_URL = ( f"https://api.twitch.tv/kraken/users/{User_ID}" ) async with request( "GET", UserInfo_URL, headers={ "Client-ID": os.environ.get("twitchclientid"), "Accept": "application/vnd.twitchtv.v5+json", }, ) as response3: async with request( "GET", UserInfo2_URL, headers={ "Client-ID": os.environ.get("twitchclientid"), "Accept": "application/vnd.twitchtv.v5+json", }, ) as response4: embed = Embed( title= f"{(await response3.json())['display_name']} User Info", colour=ctx.author.colour, timestamp=datetime.utcnow(), ) fields = [ ( "Name", (await response3.json())["display_name"], False, ), ("Bio", (await response4.json())["bio"], False), ( "Account Type", (await response4.json())["type"], True, ), ( "Creation Date", (await response3.json())["created_at"], False, ), ( "Last Updated", (await response3.json())["updated_at"], False, ), ( "Followers", (await response3.json())["followers"], True, ), ( "Partner Status", (await response3.json())["partner"], True, ), ( "Language", (await response3.json())["language"], True, ), ("URL", (await response3.json())["url"], False), ] for name, value, inline in fields: embed.add_field(name=name, value=value, inline=inline) embed.set_thumbnail( url=(await response3.json())["logo"]) if (await response3.json() )["profile_banner"] != None: embed.set_image( url=(await response3.json() )["profile_banner"]) await ctx.reply(embed=embed)
async def events(self, ctx): ''' Gets information from gbf.wiki on current and future events. ''' guild = ctx.guild if ctx.guild else 'a direct message' logging.info(f'events requested by {ctx.author} in {guild}.') thinking_msg = 'One sec, grabbing the current and upcoming events.' msg = await ctx.send(thinking_msg) now = datetime.utcnow().replace(tzinfo=pytz.utc) try: wiki = await gbfwiki.init_wiki() events = wiki.get_events() msg_current = Embed( title='Granblue Fantasy Current Events', url='https://gbf.wiki', color=Colour.teal(), timestamp=now) for event in events['current']: msg_current.add_field( name=f"[{event['title']}]({event['url']})", value=f"Ends on {event['finish']}", inline=False ) msg_upcoming = Embed( title='Granblue Fantasy Upcoming Events', url='https://gbf.wiki', color=Colour.dark_purple(), timestamp=now) for event in events['upcoming']: msg_upcoming.add_field( name=f"[{event['title']}]({event['url']})", value=f"{event['start']} to {event['finish']}", inline=False ) # send to a dedicated event channel if the message is not a DM if ctx.guild: events_channel = self.bot.get_channel(self.bot.events_channel) else: events_channel = ctx # If the event channel exists, search to see if the bot has posted # existing events before. If so, edit those instead of sending # a new embed. Best used for an events channel that is locked to # posting only by the bot. if ctx.guild: existing_messages = [] async for message in events_channel.history(limit=200): # Assume the first message to edit is the current events, # and the second message is the upcoming events. if message.author == self.bot.user and message.pinned: existing_messages.append(message) if len(existing_messages) >= 2: break if not existing_messages: await events_channel.send(embed=msg_current) await events_channel.send(embed=msg_upcoming) else: await existing_messages[0].edit(embed=msg_current) await existing_messages[1].edit(embed=msg_upcoming) else: await events_channel.send(embed=msg_current) await events_channel.send(embed=msg_upcoming) if ctx.guild: mention_msg = ( f'Hi {ctx.author.mention}! I posted the current and' f' upcoming events in {events_channel.mention}.') else: mention_msg = 'Here you go!' await msg.edit(content=mention_msg) except Exception as e: logging.warning(f'Could not retrieve events: {e}') await msg.edit( content="I couldn't retrieve the events at this time.")
async def on_message(self, message, **kwargs): assert isinstance(message, Message) client = self.client prefix = kwargs.get("prefix") if not is_valid_command(message.content, valid_commands, prefix=prefix): return else: self.stats.add(MESSAGE) def startswith(*args): for a in args: if message.content.startswith(a): return True return False if startswith(prefix + "osu"): username = message.content[len(prefix + "osu "):] t_start = time.time() user = self.osu.get_user(username) if not user: await client.send_message(message.channel, "User does not exist.") return # About inverting: this inverts the number before and after the splitting def prepare(this): if not type(this) in (float, int): return None return invert_str(",".join( split_every(str(invert_num(this)), 3))) global_rank = prepare(user.world_rank) country_rank = prepare(user.country_rank) total_score = prepare(user.total_score) ranked_score = prepare(user.ranked_score) try: acc = str(round(float(user.accuracy), 2)) + " %" except TypeError: await client.send_message(message.channel, ":warning: Something went wrong...") return pp_amount = str(int(float(user.pp))) osu_level = int(float(user.level)) avatar_url = "http://a.ppy.sh/{}".format(user.id) # Color is determined by the level range if osu_level < 10: color = Colour.darker_grey() elif osu_level < 25: color = Colour.light_grey() elif osu_level < 40: color = Colour.dark_teal() elif osu_level < 50: color = Colour.teal() elif osu_level < 75: color = Colour.dark_purple() elif osu_level < 100: color = Colour.purple() # Only the masters get the gold ;) else: color = Colour.gold() desc = "**Level**: {}\n**Rank**: \n\t" \ "**Global**: #{}\n\t" \ "**Country** (**{}**): #{}\n" \ "Total PP: **{}**".format(osu_level, global_rank, user.country, country_rank, pp_amount) embed = Embed(url=user.profile_url, description=desc, colour=color) embed.set_author(name=user.name) embed.set_thumbnail(url=avatar_url) embed.add_field(name="Total score", value=total_score) embed.add_field(name="Ranked score", value=ranked_score) embed.add_field(name="Average accuracy", value=acc) delta = int((time.time() - t_start) * 1000) embed.set_footer(text="Search took {} ms".format(delta)) try: await client.send_message(message.channel, embed=embed) except errors.HTTPException: await client.send_message( message.channel, "Something went wrong " + StandardEmoji.THINKING)
from discord import Colour from random import seed, randint from datetime import datetime seed(datetime.now()) colours = [ Colour.teal(), Colour.dark_teal(), Colour.green(), Colour.dark_green(), Colour.blue(), Colour.dark_blue(), Colour.purple(), Colour.dark_purple(), Colour.magenta(), Colour.dark_magenta(), Colour.gold(), Colour.dark_gold(), Colour.orange(), Colour.dark_orange(), Colour.red(), Colour.dark_red(), Colour.lighter_grey(), Colour.light_grey(), Colour.dark_grey(), Colour.darker_grey(), Colour.blurple(), Colour.greyple(), Colour.from_rgb(randint(0, 255), randint(0, 255), randint(0, 255)) ]
async def response_embed(ctx, title, description): embed = Embed(title=title, description=description, color=Colour.dark_purple()) message = await ctx.send(embed=embed) return message
async def stream_lookup_command(self, ctx, *, username: str): """Request some information on a specific Twitch Stream/User!\n`Username` = Twitch Username""" User_URL = f"https://api.twitch.tv/kraken/users?login={username}" async with request("GET", User_URL, headers={ 'Client-ID': os.environ.get("twitchclientid"), 'Accept': 'application/vnd.twitchtv.v5+json' }) as response: if response.status == 200: User_ID = (await response.json())['users'][0]['_id'] StreamInfo_URL = f'https://api.twitch.tv/kraken/streams/{User_ID}' async with request("GET", StreamInfo_URL, headers={ 'Client-ID': os.environ.get("twitchclientid"), 'Accept': 'application/vnd.twitchtv.v5+json' }) as response2: if response2.status == 200: if (await response2.json())['stream'] != None: embed = Embed( title= f"{(await response2.json())['stream']['channel']['display_name']} Stream Info", colour=Colour.dark_purple(), timestamp=datetime.utcnow()) fields = [ ("Name", f"{(await response2.json())['stream']['channel']['display_name']}", False), ("Title", f"{(await response2.json())['stream']['channel']['status']}", True), ("Game", f"{(await response2.json())['stream']['channel']['game']}", True), ("Viewers", f"{(await response2.json())['stream']['viewers']}", True), ("Lagnuage", f"{(await response2.json())['stream']['channel']['broadcaster_language']}", True), ("Followers", f"{(await response2.json())['stream']['channel']['followers']}", True), ("Patner Status", f"{(await response2.json())['stream']['channel']['partner']}", True), ("Went live at:", f"{(await response2.json())['stream']['created_at']}", True), ("URL", (await response2.json() )['stream']['channel']["url"], False) ] for name, value, inline in fields: embed.add_field(name=name, value=value, inline=inline) embed.set_image( url=(await response2.json() )['stream']['preview']['large']) embed.set_thumbnail( url=(await response2.json() )['stream']['channel']['logo']) await ctx.send(embed=embed) else: UserInfo_URL = f'https://api.twitch.tv/kraken/channels/{User_ID}' UserInfo2_URL = f'https://api.twitch.tv/kraken/users/{User_ID}' async with request( "GET", UserInfo_URL, headers={ 'Client-ID': os.environ.get("twitchclientid"), 'Accept': 'application/vnd.twitchtv.v5+json' }) as response3: async with request( "GET", UserInfo2_URL, headers={ 'Client-ID': os.environ.get("twitchclientid"), 'Accept': 'application/vnd.twitchtv.v5+json' }) as response4: embed = Embed( title= f"{(await response3.json())['display_name']} User Info", colour=ctx.author.colour, timestamp=datetime.utcnow()) fields = [ ("Name", (await response3.json())["display_name"], False), ("Bio", (await response4.json())["bio"], False), ("Account Type", (await response4.json())["type"], True), ("Creation Date", (await response3.json())["created_at"], False), ("Last Updated", (await response3.json())["updated_at"], False), ("Followers", (await response3.json())["followers"], True), ("Partner Status", (await response3.json())["partner"], True), ("Language", (await response3.json())["language"], True), ("URL", (await response3.json())["url"], False) ] for name, value, inline in fields: embed.add_field(name=name, value=value, inline=inline) embed.set_thumbnail( url=(await response3.json())["logo"]) if (await response3.json() )['profile_banner'] != None: embed.set_image( url=(await response3.json() )["profile_banner"]) await ctx.send(embed=embed)
async def editmaps(self, ctx, operation="", map_id: int = 0): if not has_permissions(ctx, ADMIN_ROLE): await ctx.send("You do not have sufficient permissions to perform this command", hidden=True) return False def check(m): return m.author == ctx.author and m.channel == ctx.channel map_id = int(map_id) if operation == "add": with open("utils/maps.json", "r+") as file: data = load(file) for k, v in data.items(): if int(v) == map_id: return await error_embed(ctx, "Map already exists") embed = Embed(title="Adding map to database", description="Enter the name of the map", color=Colour.dark_purple()) embed.set_footer(text="Type \"cancel\" to cancel") message = await ctx.send(embed=embed) response = await self.bot.wait_for("message", check=check) if not response.content: return await error_embed(ctx, "Not a string") if response.content.lower() == "cancel": return await ctx.send(embed=Embed(description="❌ Adding map cancelled", color=Colour.dark_red())) name = response.content embed = Embed(title="Adding map to database", description="Would you like to add an image?", color=Colour.dark_purple()) embed.set_footer(text="Type \"y/yes\" to add map with an image\nType \"n/no\" to add map without an image\nType \"cancel\" to cancel map adding") message = await ctx.send(embed=embed) response = await self.bot.wait_for("message", check=check) if response.content.lower() in ["done", "finished", "yes", "y"]: #add map if y embed = Embed(title="Adding map to database", description="This can be a direct upload, or a direct link to an image (not supported yet)", color=Colour.dark_purple()) message = await ctx.send(embed=embed) response = await self.bot.wait_for("message", check=check) #Send image here if not response.attachments: return await error_embed(ctx, "No image attached") if not response.attachments[0].content_type.startswith("image"): return await error_embed(ctx, "File uploaded is not image") attachment = response.attachments[0] embed = Embed(title="Confirm addition (y/n)", description=f"Are you sure you want to add {name} ({map_id})?", color=Colour.dark_purple()) embed.set_image(url=attachment.url) message = await ctx.send(embed=embed) response = await self.bot.wait_for("message", check=check) is_correct = response.content.lower() == "y" or response.content.lower() == "yes" if not is_correct: return await ctx.send(embed=Embed(description="❌ Adding map cancelled", color=Colour.dark_red())) await attachment.save(f"assets/map_screenshots/{map_id}.jpg") compress(f"assets/map_screenshots/{map_id}.jpg") await response_embed(ctx, "✅ Map added", "") elif response.content.lower() in ["no", "n"]: await response_embed(ctx, "✅ Map added", "") elif response.content.lower() == "cancel": return await ctx.send(embed=Embed(description="❌ Adding map cancelled", color=Colour.dark_red())) else: return await ctx.send(embed=Embed(description="❌ Adding map cancelled, please type yes, no or cancel next time", color=Colour.dark_red())) new_data = {name: map_id} data = None with open("utils/maps.json", "r+") as file: data = load(file) data.update(new_data) with open("utils/maps.json", "w") as file: dump(data, file, sort_keys=True, indent=4) elif operation == "del": name = None with open("utils/maps.json", "r+") as file: data = load(file) for k, v in data.items(): if int(v) == map_id: name = k data.pop(k) break if name is None: return await error_embed(ctx, "Map not found") try: file = File(f"assets/map_screenshots/{map_id}.jpg", filename=f"{map_id}.png") embed = Embed(file=file, title="Confirm deletion (y/n)", description=f"Are you sure you want to delete **{name}** ({map_id})?", color=Colour.dark_purple()) embed.set_image(url=f"attachment://{map_id}.png") message = await ctx.send(file=file, embed=embed) except FileNotFoundError: embed = Embed(title="Confirm deletion (y/n)", description=f"Are you sure you want to delete **{name}** ({map_id})?", color=Colour.dark_purple()) message = await ctx.send(embed=embed) response = await self.bot.wait_for("message", check=check) is_correct = response.content.lower() == "y" or response.content.lower() == "yes" if not is_correct: return await ctx.send(embed=Embed(description="❌ Deleting map cancelled", color=Colour.dark_red())) with open("utils/maps.json", "w") as file: dump(data,file, sort_keys=True, indent=4) if os.path.exists(f"assets/map_screenshots/{map_id}.jpg"): os.remove(f"assets/map_screenshots/{map_id}.jpg") return await response_embed(ctx, "✅ Map deleted", "")
async def create_list_pages(bot, ctx, title: str, info: list, if_empty: str = "Empty List", sep: str = "\n", elements_per_page: int = 10, thumbnails=None, can_be_reversed=False, random_item=False): if not info: await ctx.send(embed=Embed( title=title, description=if_empty, colour=Colour.dark_red())) return contents = [] num_pages = ceil(len(info) / elements_per_page) page = "" current_page = 1 for index, value in enumerate(info): page = page + str(value + sep) if not (index + 1) % elements_per_page: contents.append(page) page = "" contents.append(page) embed = Embed(title=title, description=contents[current_page - 1], colour=Colour.dark_purple()) embed.set_footer(text=f"Page {current_page}/{num_pages}") if thumbnails: if len(thumbnails) == 1: embed.set_thumbnail(url=thumbnails[0]) else: embed.set_thumbnail(url=thumbnails[current_page - 1]) buttons = [] if num_pages != 1: buttons.append( manage_components.create_button(ButtonStyle.primary, emoji="◀")) buttons.append( manage_components.create_button(ButtonStyle.primary, emoji="▶")) if can_be_reversed: buttons.append( manage_components.create_button(ButtonStyle.secondary, label="Reverse")) if random_item: buttons.append( manage_components.create_button(ButtonStyle.secondary, label="Shuffle")) buttons.append( manage_components.create_button(ButtonStyle.danger, label="Close")) action_row = manage_components.create_actionrow(*buttons) message = await ctx.send(embed=embed, components=[action_row]) while True: try: button_context: ComponentContext = await manage_components.wait_for_component( bot, timeout=120, components=action_row) if button_context.author.id != ctx.author.id: await button_context.send( "These buttons belong to someone else - try using the command yourself", hidden=True) continue except TimeoutError: embed.set_footer( text=f"Page {current_page}/{num_pages} (Timed Out)") await message.edit(embed=embed, components=None) break if "emoji" in button_context.component.keys(): if button_context.component["emoji"]["name"] == "▶": if current_page != num_pages: current_page += 1 embed = Embed(title=title, description=contents[current_page - 1], colour=Colour.dark_purple()) elif current_page == num_pages and num_pages != 1: # Jump from last page to first page current_page = 1 embed = Embed(title=title, description=contents[current_page - 1], colour=Colour.dark_purple()) elif button_context.component["emoji"]["name"] == "◀": if current_page == 1 and num_pages != 1: # Jump from first page to last page current_page = num_pages embed = Embed(title=title, description=contents[current_page - 1], colour=Colour.dark_purple()) elif current_page > 1: current_page -= 1 embed = Embed(title=title, description=contents[current_page - 1], colour=Colour.dark_purple()) if thumbnails: if len(thumbnails) == 1: embed.set_thumbnail(url=thumbnails[0]) else: embed.set_thumbnail(url=thumbnails[current_page - 1]) embed.set_footer(text=f"Page {current_page}/{num_pages}") await button_context.edit_origin(embed=embed) elif "label" in button_context.component.keys(): if button_context.component[ "label"] == "Reverse" and can_be_reversed: info.reverse() contents = [] num_pages = ceil(len(info) / elements_per_page) page = "" for index, value in enumerate(info): page = page + str(value + sep) if not (index + 1) % elements_per_page: contents.append(page) page = "" contents.append(page) current_page = 1 embed = Embed(title=title, description=contents[current_page - 1], colour=Colour.dark_purple()) if thumbnails: if len(thumbnails) == 1: embed.set_thumbnail(url=thumbnails[0]) else: embed.set_thumbnail(url=thumbnails[current_page - 1]) embed.set_footer(text=f"Page {current_page}/{num_pages}") await button_context.edit_origin(embed=embed) elif button_context.component["label"] == "Shuffle" and random_item: embed = Embed(title=title, description=choice(info), colour=Colour.dark_purple()) await button_context.edit_origin(embed=embed) elif button_context.component["label"] == "Close": await message.edit(content="Closing message..", embed=None, components=None) await button_context.edit_origin(content="List Pages Closed") # This requires 2 requests, one to actually clear the embed and components and another to show to discord the interaction succeeded # Hopefully a change is made to the slash lib so it supports removing the embed/components break
async def user(self, ctx, discord_tag: User = None, action_type="get", variable_name=None, value=None): """ Allows a PUG Mod to edit information about a user. Usage: user @Tom <get/set> <variable_name> <value> Examples: user @Tom get returns user profile user @Tom set elo [elo] sets user ELO """ if not has_permissions(ctx, MOD_ROLE): await ctx.send( "You do not have sufficient permissions to perform this command", hidden=True) return False user = self.bot.get_user(discord_tag.id) if action_type == "get": try: player = Player.from_discord_id(user.id) except PlayerDoesNotExistError: await error_embed(ctx, "Player does not exist") return info = "" for key in player.__dict__.keys(): info += f"**{key}**: {getattr(player, key)}\n" embed = Embed(description=info, title=f"User Profile - {user.name}", color=Colour.dark_purple()) await ctx.send(embed=embed) elif action_type == "set": try: player = Player.from_discord_id(user.id) except PlayerDoesNotExistError: await error_embed(ctx, "Player does not exist") return if variable_name: if value: if variable_name == "username": old_username = player.update_minecraft_username() try: player.change_minecraft_username(value) await success_embed( ctx, f"Changed {discord_tag.mention}'s username: **{old_username}** -> **{value}**" ) except UsernameAlreadyExistsError: await error_embed( ctx, f"Username **{value}** is already in the database" ) except UsernameDoesNotExistError: await error_embed( ctx, f"Username **{value}** is not a valid username" ) elif variable_name == "discord": value = value[3:-1] if value.isdigit(): user = self.bot.get_user(int(value)) if user: try: player.change_discord_id(user.id) await success_embed( ctx, f"Changed discord user: {discord_tag.mention} -> {user.mention}" ) except DiscordAlreadyExistsError: await error_embed( ctx, f"User {user.mention} is already in the database" ) else: await error_embed(ctx, "Value must be a User") else: await error_embed(ctx, "Value must be a User") elif variable_name == "elo": old_elo = player.get_elo() if value.isdigit(): value = int(value) if player.set_elo(value): await success_embed( ctx, f"Set {discord_tag.mention}'s elo: **{old_elo}** -> **{value}**" ) else: await error_embed( ctx, f"Elo given (**{value}**) is below Elo floor (**{ELO_FLOOR}**)" ) else: await error_embed(ctx, "Value must be an int") else: old_priority = player.get_priority() if value.isdigit(): value = int(value) if player.set_priority(value): await success_embed( ctx, f"Set {discord_tag.mention}'s priority: **{old_priority}** -> **{value}**" ) else: await error_embed( ctx, f"Priority given (**{value}**) is negative" ) else: await error_embed(ctx, "Value must be an int") else: await error_embed(ctx, "No value inputted") else: await error_embed(ctx, "No variable name inputted") else: await error_embed(ctx, "Invalid action argument. Use 'get' or 'set'")
async def register(self, ctx, minecraft_username=""): """ Registers Minecraft username to Discord. Required to sign up for PUGs. Usage: register <minecraft_username> Example: register Ninsanity """ if not minecraft_username: embed = Embed(title="Error ❌", description="Missing argument <minecraft_username>", color=Colour.dark_red()) embed.add_field(name="Example", value="-register Ninsanity") await ctx.send(embed=embed) return uuid = MojangAPI.get_uuid(minecraft_username) if uuid: condition = Player.player_check(uuid, ctx.author.id) if not condition: if check_user_requests(ctx.author.id): await error_embed( ctx, "You have already submitted a register request") else: request_channel = self.bot.get_channel( REGISTER_REQUESTS_CHANNEL) embed = Embed( title=f"Register Request: {minecraft_username}", description= f"React below to verify {ctx.author.mention}", colour=Colour.dark_purple()) embed.set_thumbnail( url=f"https://cravatar.eu/helmavatar/{uuid}/128.png") message = await request_channel.send(embed=embed) await message.add_reaction("✅") await message.add_reaction("❌") if add_register_request(uuid, ctx.author.id, minecraft_username, message.id): await ctx.send(embed=Embed( title="Registration Pending", description= f"Requested to register **{minecraft_username}**" f" to {ctx.author.mention}", color=Colour.dark_purple())) else: await error_embed( ctx, "There was an error storing your register request. Contact a PUG Dev" ) elif condition == 1: await ctx.send(embed=Embed( title="Error ❌", description= f"**{minecraft_username}** is already registered", color=Colour.dark_red())) else: await ctx.send(embed=Embed( title="Error ❌", description=f"{ctx.author.mention} is already registered", color=Colour.dark_red())) else: await ctx.send(embed=Embed( title="Error ❌", description=f"**{minecraft_username}** does not exist", color=Colour.dark_red()))