def _getStatusEmbed(self, servicesInfo): embed = discord.Embed(title="Server Statuses") successCount = 0 totalCount = 9 for service in servicesInfo: embed.add_field(name=service["name"], value=upperFirst(service["statusClass"])) if service["statusClass"] == "good" or service["statusClass"] == "success": successCount += 1 failCount = totalCount - successCount # Switch between green and red depending on number of failed services redPercent = (failCount / totalCount) * 255 greenPercent = (successCount / totalCount) * 255 embed.colour = Colour.from_rgb(int(redPercent), int(greenPercent), 0) if failCount > 0: string = "are {0} services".format(failCount) if failCount == 1: string = "is 1 service" embed.add_field(name="Overall Status", value="There may be some latency issues because there {0} not operating at full capacity.".format(string)) else: embed.add_field(name="Overall Status", value="All services running at full capacity.") embed.timestamp = dt.utcnow() embed.set_footer(text="SteamAPI from http://steamstat.us/ .") return embed
async def add(self, ctx, *, role: CustomRoleConverter): """ Adds a role to the list that can be assigned """ # Call the universal setup command to pull the roles from the DB role_me, role_me_lvl, role_me_roles, roles = await self.setup_role_me(ctx) if role_me == "perms": return role_me_roles = self.bot.database.get(ctx.guild.id, self.guild_storage.columns.role_me_roles) if not isinstance(role, discord.Role): await ctx.send("Could not find role! Creating blank role now :crayon: ") role = await ctx.guild.create_role(name=role, colour=Colour.orange(), mentionable=True, reason="Role automagically created by GAF Bot for the role list") if role.position >= ctx.author.top_role.position: await ctx.send("Unable to add role due to Hierarchy") else: role_me_roles.append(role.id) self.bot.database.set(ctx.guild.id, self.guild_storage.columns.role_me_roles, role_me_roles) await ctx.send("`Added {} to the role list`".format(role.name))
class TypeProps(): """Represents the properties of how a type should be represented (e.g. emoji, name, colour).""" def __init__(self, emoji: str, title: str, colour: Colour, **kwargs): self.emoji = emoji self.title = title self.colour = colour self.show_history = False self.show_in_history = False self.show_context = False for key, value in kwargs.items(): setattr(self, key, value) colour_ranked = Colour.from_rgb(255, 200, 90) colour_qualified = Colour.from_rgb(255, 75, 100) colour_nominated = Colour.from_rgb(50, 150, 255) colour_discussion = Colour.from_rgb(65, 65, 65) colour_resolve = Colour.from_rgb(100, 200, 100) colour_reopen = Colour.from_rgb(255, 160, 70) colour_news = Colour.from_rgb(255, 160, 200) colour_added = Colour.from_rgb(130, 235, 125) colour_removed = Colour.from_rgb(200, 160, 230) type_props = { types.RANK: TypeProps(":sparkling_heart:", "Ranked", colour_ranked, show_history=True), types.LOVE: TypeProps(":gift_heart:", "Loved", colour_ranked, show_history=True), types.QUALIFY:
async def horizon_error_msg(destination, error): horizon_err = Embed(title=f':exclamation: Horizon API error :exclamation:', colour=Colour.red()) horizon_err.add_field(name=f'Error Details', value=f'{error}') await destination.send(embed=horizon_err)
async def superstarify(self, ctx: Context, member: Member, duration: str, *, forced_nick: str = None): """ This command will force a random superstar name (like Taylor Swift) to be the user's nickname for a specified duration. If a forced_nick is provided, it will use that instead. :param ctx: Discord message context :param ta: If provided, this function shows data for that specific tag. If not provided, this function shows the caller a list of all tags. """ log.debug( f"Attempting to superstarify {member.display_name} for {duration}. " f"forced_nick is set to {forced_nick}.") embed = Embed() embed.colour = Colour.blurple() params = {"user_id": str(member.id), "duration": duration} if forced_nick: params["forced_nick"] = forced_nick response = await self.bot.http_session.post(URLs.site_superstarify_api, headers=self.headers, json=params) response = await response.json() if "error_message" in response: log.warning( "Encountered the following error when trying to superstarify the user:\n" f"{response.get('error_message')}") embed.colour = Colour.red() embed.title = random.choice(NEGATIVE_REPLIES) embed.description = response.get("error_message") return await ctx.send(embed=embed) else: forced_nick = response.get('forced_nick') end_time = response.get("end_timestamp") image_url = response.get("image_url") old_nick = member.display_name embed.title = "Congratulations!" embed.description = ( f"Your previous nickname, **{old_nick}**, was so bad that we have decided to change it. " f"Your new nickname will be **{forced_nick}**.\n\n" f"You will be unable to change your nickname until \n**{end_time}**.\n\n" "If you're confused by this, please read our " f"[official nickname policy]({NICKNAME_POLICY_URL}).") embed.set_image(url=image_url) # Log to the mod_log channel log.trace( "Logging to the #mod-log channel. This could fail because of channel permissions." ) mod_log_message = ( f"**{member.name}#{member.discriminator}** (`{member.id}`)\n\n" f"Superstarified by **{ctx.author.name}**\n" f"Old nickname: `{old_nick}`\n" f"New nickname: `{forced_nick}`\n" f"Superstardom ends: **{end_time}**") await self.modlog.send_log_message( icon_url=Icons.user_update, colour=Colour.gold(), title="Member Achieved Superstardom", text=mod_log_message, thumbnail=member.avatar_url_as(static_format="png")) await self.moderation.notify_infraction( user=member, infr_type="Superstarify", duration=duration, reason= f"Your nickname didn't comply with our [nickname policy]({NICKNAME_POLICY_URL})." ) # Change the nick and return the embed log.debug("Changing the users nickname and sending the embed.") await member.edit(nick=forced_nick) await ctx.send(embed=embed)
async def on_message_edit(self, msg_before: discord.Message, msg_after: discord.Message) -> None: """Log message edit event to message change log.""" if (not msg_before.guild or msg_before.guild.id != GuildConstant.id or msg_before.channel.id in GuildConstant.modlog_blacklist or msg_before.author.bot): return self._cached_edits.append(msg_before.id) if msg_before.content == msg_after.content: return author = msg_before.author author_str = escape_markdown(str(author)) channel = msg_before.channel channel_name = f"{channel.category}/#{channel.name}" if channel.category else f"#{channel.name}" # Getting the difference per words and group them by type - add, remove, same # Note that this is intended grouping without sorting diff = difflib.ndiff(msg_before.clean_content.split(), msg_after.clean_content.split()) diff_groups = tuple( (diff_type, tuple(s[2:] for s in diff_words)) for diff_type, diff_words in itertools.groupby(diff, key=lambda s: s[0])) content_before: t.List[str] = [] content_after: t.List[str] = [] for index, (diff_type, words) in enumerate(diff_groups): sub = ' '.join(words) if diff_type == '-': content_before.append(f"[{sub}](http://o.hi)") elif diff_type == '+': content_after.append(f"[{sub}](http://o.hi)") elif diff_type == ' ': if len(words) > 2: sub = ( f"{words[0] if index > 0 else ''}" " ... " f"{words[-1] if index < len(diff_groups) - 1 else ''}") content_before.append(sub) content_after.append(sub) response = (f"**Author:** {author_str} (`{author.id}`)\n" f"**Channel:** {channel_name} (`{channel.id}`)\n" f"**Message ID:** `{msg_before.id}`\n" "\n" f"**Before**:\n{' '.join(content_before)}\n" f"**After**:\n{' '.join(content_after)}\n" "\n" f"[Jump to message]({msg_after.jump_url})") if msg_before.edited_at: # Message was previously edited, to assist with self-bot detection, use the edited_at # datetime as the baseline and create a human-readable delta between this edit event # and the last time the message was edited timestamp = msg_before.edited_at delta = humanize_delta( relativedelta(msg_after.edited_at, msg_before.edited_at)) footer = f"Last edited {delta} ago" else: # Message was not previously edited, use the created_at datetime as the baseline, no # delta calculation needed timestamp = msg_before.created_at footer = None await self.send_log_message(Icons.message_edit, Colour.blurple(), "Message edited", response, channel_id=Channels.message_log, timestamp_override=timestamp, footer=footer)
def get_default_embed(description): return Embed.from_dict({ 'description': description, 'color': Colour.blue().value, })
async def readme(self, ctx: Context, operand: str = "", channel_id: str = "", msg_send_interval: int = 0): """ Allows generating, sending and manipulation of JSON file containing the info needed to create and send the embeds for the #readme channel. Only ROOT_ROLE_ID users have the permissions need to use this command. """ operand = operand.lower() # The supplied operand is incorrect. if not (operand in README_SEND_ALIASES + README_RECV_ALIASES): incorrect_operand_embed = Embed( colour=0x673ab7, description=":shrug: **Invalid readme operand supplied.**") await ctx.message.delete() await ctx.send(embed=incorrect_operand_embed) # User missed out the channel_id for certain commands. elif (channel_id == "" and operand in README_SEND_ALIASES): misssing_channel_embed = Embed( colour=0xff5722, description= ":facepalm: **Whoops, you missed out the channel ID! Try again.**" ) await ctx.message.delete() await ctx.send(embed=misssing_channel_embed) # Process the request. else: # Let's create a series of #readme-capable embeds. If something is uploaded, # It will attempt to use that file for the readme, if omitted, it will use # the default JSONifed readme file and send that into the channel instead. if operand in README_SEND_ALIASES: try: # Much pain was had fixing this. Please, get some help and install mypy type checking. channel_id: int = int(channel_id[2:-1] if channel_id[0] == "<" else channel_id) usr_confirmation_embed = Embed( colour=0x4caf50, description= ":white_check_mark: **Creating readme using uploaded config file.**" ) # The user has uploaded a config. if ctx.message.attachments != []: json_file_location = [ _.url for _ in ctx.message.attachments ][0] # GETs the attachment data. async with ClientSession() as session: async with session.get( json_file_location) as response: if response.status == 200: resp_text = await response.text() json_config = load(StringIO(resp_text)) await ctx.send(embed=usr_confirmation_embed) # No config uploaded, just use default config file. else: with open("cdbot/data/readme.json", "rb") as default_json: json_config = load(default_json) usr_confirmation_embed.description = ( ":ballot_box_with_check: " "**Creating readme using default config file.**") await ctx.send(embed=usr_confirmation_embed) await ctx.message.delete() for section in json_config: # Initialise our message and embed variables each loop. # This is to prevent leftover data from being re-sent. msg_content, current_embed = None, None # The part which handles general messages. if "content" in json_config[section]: msg_content = json_config[section]["content"] # We have an embed. Call in the Seahawks. if "embed" in json_config[section]: current_embed = Embed() msg_embed = json_config[section]["embed"] if "title" in msg_embed: current_embed.title = msg_embed["title"] if "description" in msg_embed: current_embed.description = msg_embed[ "description"] if "color" in msg_embed: current_embed.colour = Colour( int(msg_embed["color"], 16)) # Parse the fields, if there are any. if "fields" in msg_embed: for current_field in msg_embed["fields"]: # Add the fields to the current embed. current_embed.add_field( name=current_field["name"], value=current_field["value"]) # Send the message. requested_channel = self.bot.get_channel(channel_id) if (msg_content is not None and current_embed is None): await requested_channel.send(content=msg_content) elif (current_embed is not None and msg_content is None): await requested_channel.send(embed=current_embed) else: await requested_channel.send(content=msg_content, embed=current_embed) # User has requested a delay between each message being sent. if (0 < msg_send_interval < 901): await sleep(msg_send_interval) # Send the trailing embed message constant. await requested_channel.send(content=END_README_MESSAGE) except (Exception): parse_fail_embed = Embed( colour=0x673ab7, description= ":x: **Error parsing JSON file, please ensure its valid!**" ) await ctx.message.delete() await ctx.send(embed=parse_fail_embed) # Pull the readme JSON constant files and slide it into the user's DMs. elif operand in README_RECV_ALIASES: # Slide it to the user's DMs. requesting_user = await self.bot.fetch_user( ctx.message.author.id) await requesting_user.send( content="Hey, here's your config file!", file=File(fp="cdbot/data/readme.json", filename='readme.json')) await ctx.message.delete() await ctx.send(embed=Embed( colour=0x009688, description=":airplane: **Flying in, check your DMs!**"))
async def ledger(self, ctx, ledger_number: int): try: data = self.hor_ledgers.ledger(sequence=ledger_number).call() if data: operations_count = len( requests.get( f'https://horizon-testnet.stellar.org/ledgers/{ledger_number}/operations' ).json()['_embedded']["records"]) effects_count = len( requests.get( f'https://horizon-testnet.stellar.org/ledgers/{ledger_number}/effects' ).json()['_embedded']["records"]) payments_count = len( requests.get( f'https://horizon-testnet.stellar.org/ledgers/{ledger_number}/payments' ).json()['_embedded']["records"]) transactions_count = len( requests.get( f'https://horizon-testnet.stellar.org/ledgers/{ledger_number}/transactions' ).json()['_embedded']["records"]) ledger_info = Embed( title= f':ledger: Ledger :id: {ledger_number} Information :ledger:', description= 'Bellow is represent information for requested ledger.', colour=Colour.lighter_gray()) ledger_info.add_field( name=':white_circle: Paging Token :white_circle: ', value=f'`{data["paging_token"]}`', inline=False) ledger_info.add_field(name=':timer: Closing Time :timer: ', value=f'{data["closed_at"]}') ledger_info.add_field(name=':hash: Ledger Hash :hash:', value=f'`{data["hash"]}`', inline=False) ledger_info.add_field( name=':abacus: Transaction Count :abacus: ', value=f'`{data["successful_transaction_count"]}`', inline=False) ledger_info.add_field( name=':wrench: Operations Count :wrench: ', value=f'`{data["operation_count"]}`', inline=False) ledger_info.add_field( name=':x: Failed Transactions :x: ', value=f'`{data["failed_transaction_count"]}`', inline=False) ledger_info.add_field( name=':moneybag: Total Existing XLM :moneybag: ', value=f'`{data["total_coins"]} XLM`', inline=False) ledger_info.add_field( name=':money_mouth: Base Fee :money_mouth: ', value= f'`{format(round(data["base_fee_in_stroops"] / 10000000, 7), ".7f")} XLM`', inline=False) ledger_info.add_field(name=':bath: Fee Pool :bath: ', value=f'`{data["fee_pool"]} XLM`', inline=False) ledger_info.add_field( name=':arrow_forward: Protocol Version :arrow_forward: ', value=f'`{data["protocol_version"]}`', inline=False) ledger_info.add_field( name=f':person_running: Ledger Activity :person_running: ', value= f'Operations: [{operations_count}]({data["_links"]["operations"]["href"]}) \n' f'Effects: [{effects_count}]({data["_links"]["effects"]["href"]})\n' f'Payments: [{payments_count}]({data["_links"]["payments"]["href"]}) \n' f'Transactions: [{transactions_count}]({data["_links"]["transactions"]["href"]})' ) ledger_info.set_footer( text='Click on number to expand details') await ctx.author.send(embed=ledger_info) except BadRequestError as e: extras = e.extras await horizon_error_msg(destination=ctx.message.author, error=extras["reason"])
class Colours: white = Colour(0xFFFFFF) blurple = Colour(0x7289DA) gold = Colour(0xE4E415) diamond = Colour(0xECF5FF)
async def on_message(self,message): if not message.author.bot: is_help = False ID_bot_mention = '<@!613269904963141643>' ID_bot_mention_without_exclamation_mark = '<@613269904963141643>' role_bot = '<@&698575036310618222>' was_already = False if ID_bot_mention or ID_bot_mention_without_exclamation_mark or role_bot in message.content: I = message.guild.get_member(506438836943978496) if ID_bot_mention in message.content: result = select("Question",["question","answer"],f"question = '{message.content.replace(ID_bot_mention,'')}'") elif ID_bot_mention_without_exclamation_mark in message.content: result = select("Question",["question","answer"],f"question = '{message.content.replace(ID_bot_mention_without_exclamation_mark,'')}'") else: result = select("Question",["question","answer"],f"question = '{message.content.replace(role_bot,'')}'") for row in result: if row[0] == message.content.replace(ID_bot_mention,'') or message.content.replace(ID_bot_mention_without_exclamation_mark,'') or message.content.replace(role_bot,''): was_already = True if message.content == ".rank" or message.content == ".card": is_help = True print(f"{message.author} : {message.content} channel {message.channel}") channel_logs = message.guild.get_channel(688373372945694725) em = Embed(description = f"{message.author} : `{message.content}` channel {message.channel}", colour = Colour.from_rgb(0, 0, 201)) await channel_logs.send(embed = em) plus_lvl = 0 if len(message.content) >= 5 and not is_help: result = select("Members",["xp","lvl"],f"id = {message.author.id}") for row in result: if len(message.content) >= 15: exp_plus = int(row[0]) + randint(10,19) update("Members",["xp"],[f"{exp_plus}"],f"id = {message.author.id}") lvl_up = exp_plus/(int(row[1]) * 50) if int(row[1]) <= lvl_up: plus_lvl = int(row[1]) + 1 await message.channel.send(f'Ура <@!{message.author.id}>, у тебя новый лвл. Теперь у тебя {plus_lvl} лвл. Ты можешь это проверить при помоши `.rank`.') update("Members",["lvl"],[f"{plus_lvl}"],f"id = {message.author.id}") else: exp_plus = int(row[0]) + randint(3,7) update("Members",["xp"],[f"{exp_plus}"],f"id = {message.author.id}") lvl_up = exp_plus/(int(row[1]) * 50) if int(row[1]) <= lvl_up: plus_lvl = int(row[1]) + 1 await message.channel.send(f'Ура <@!{message.author.id}>, у тебя новый лвл. Теперь у тебя {plus_lvl} лвл. Ты можешь это проверить при помоши `.rank`.') update("Members",["lvl"],[f"{plus_lvl}"],f"id = {message.author.id}") if plus_lvl == 5: mem5 = message.guild.get_member(message.author.id) role5 = message.guild.get_role(643949984194101273) role_del5 = message.guild.get_role(643902599661223951) await mem5.add_roles(role5) await mem5.remove_roles(role_del5) await message.channel.send(f"Вам выдана роль `{str(role5).lower()}`") if plus_lvl == 10: mem6 = message.guild.get_member(message.author.id) role6 = message.guild.get_role(643902599468285962) role_del6 = message.guild.get_role(643949984194101273) await mem6.add_roles(role6) await mem6.remove_roles(role_del6) await message.channel.send(f"Вам выдана роль `{str(role6).lower()}`") if plus_lvl == 25: mem7 = message.guild.get_member(message.author.id) role7 = message.guild.get_role(680859240583266509) role_del7 = message.guild.get_role(643902599468285962) await mem7.add_roles(role7) await mem7.remove_roles(role_del7) await message.channel.send(f"Вам выдана роль `{str(role7).lower()}`") if plus_lvl == 100: mem8 = message.guild.get_member(message.author.id) role8 = message.guild.get_role(643902598289686556) role_del8 = message.guild.get_role(680859240583266509) await mem8.add_roles(role8) await mem8.remove_roles(role_del8) await message.channel.send(f"Вам выдана роль `{str(role8).lower()}`") while True: try: member = 0 members = message.guild.members for i in range(len(members)): if members[i].status == Status.online: member += 1 elif members[i].status == Status.idle: member += 1 elif members[i].status == Status.dnd: member += 1 elif members[i].status == Status.invisible: member += 1 in_online = message.guild.get_channel(703248000839057459) await in_online.edit(name=f'Людей в сети: {member}') except: pass
async def on_message_edit(self,before,after): if not before.author.bot: channel_logs = before.guild.get_channel(688373372945694725) await channel_logs.send(embed = Embed(description = f"{before.author} изменил сообщение `{before.content}` на `{after.content}`",colour = Colour.orange()))
async def on_message_delete(self,message): if not message.author.bot: print(f"{message.author} delete {message.content} channel {message.channel}") channel_logs = message.guild.get_channel(688373372945694725) await channel_logs.send(embed = Embed(description = f"{message.author} delete `{message.content}` channel {message.channel}", colour = Colour.from_rgb(207,192,0)))
async def _filter_message(self, msg: Message): """ Whenever a message is sent or edited, run it through our filters to see if it violates any of our rules, and then respond accordingly. """ # Should we filter this message? role_whitelisted = False if type(msg.author) is Member: # Only Member has roles, not User. for role in msg.author.roles: if role.id in Filter.role_whitelist: role_whitelisted = True filter_message = ( msg.channel.id not in Filter.channel_whitelist # Channel not in whitelist and not role_whitelisted # Role not in whitelist and not msg.author.bot # Author not a bot ) # If we're running the bot locally, ignore role whitelist and only listen to #dev-test if DEBUG_MODE: filter_message = not msg.author.bot and msg.channel.id == Channels.devtest # If none of the above, we can start filtering. if filter_message: for filter_name, _filter in self.filters.items(): # Is this specific filter enabled in the config? if _filter["enabled"]: triggered = await _filter["function"](msg.content) if triggered: message = ( f"The {filter_name} {_filter['type']} was triggered " f"by **{msg.author.name}#{msg.author.discriminator}** " f"(`{msg.author.id}`) in <#{msg.channel.id}> with [the " f"following message]({msg.jump_url}):\n\n" f"{msg.content}") log.debug(message) # Send pretty mod log embed to mod-alerts await self.mod_log.send_log_message( icon_url=Icons.filtering, colour=Colour(Colours.soft_red), title=f"{_filter['type'].title()} triggered!", text=message, thumbnail=msg.author.avatar_url_as( static_format="png"), channel_id=Channels.mod_alerts, ping_everyone=Filter.ping_everyone, ) # If this is a filter (not a watchlist), we should delete the message. if _filter["type"] == "filter": await msg.delete() break # We don't want multiple filters to trigger
async def get_command(self, ctx: Context, tag_name=None): """ Get a list of all tags or a specified tag. :param ctx: Discord message context :param tag_name: If provided, this function shows data for that specific tag. If not provided, this function shows the caller a list of all tags. """ def _command_on_cooldown(tag_name) -> bool: """ Check if the command is currently on cooldown. The cooldown duration is set in constants.py. This works on a per-tag, per-channel basis. :param tag_name: The name of the command to check. :return: True if the command is cooling down. Otherwise False. """ now = time.time() cooldown_conditions = ( tag_name and tag_name in self.tag_cooldowns and (now - self.tag_cooldowns[tag_name]["time"]) < TAG_COOLDOWN and self.tag_cooldowns[tag_name]["channel"] == ctx.channel.id) if cooldown_conditions: return True return False if _command_on_cooldown(tag_name): time_left = TAG_COOLDOWN - (time.time() - self.tag_cooldowns[tag_name]["time"]) print( f"That command is currently on cooldown. Try again in {time_left:.1f} seconds." ) return embed = Embed() tags = [] tag_data = await self.get_tag_data(tag_name) # If we found something, prepare that data if tag_data: embed.colour = Colour.blurple() if tag_name: embed.title = tag_name self.tag_cooldowns[tag_name] = { "time": time.time(), "channel": ctx.channel.id } else: embed.title = "**Current tags**" if isinstance(tag_data, list): tags = [f"**»** {tag['tag_name']}" for tag in tag_data] tags = sorted(tags) else: embed.description = tag_data['tag_content'] # If not, prepare an error message. else: embed.colour = Colour.red() embed.description = "**There are no tags in the database!**" if isinstance(tag_data, dict): embed.description = f"Unknown tag: **{tag_name}**" if tag_name: embed.set_footer( text="To show a list of all tags, use bot.tags.get().") embed.title = "Tag not found" # Paginate if this is a list of all tags if tags: return await LinePaginator.paginate( (lines for lines in tags), ctx, embed, footer_text="To show a tag, type bot.tags.get <tagname>.", empty=False, max_lines=15) return await ctx.send(embed=embed)
async def list_language(self, ctx, language: str=''): """ Displays TTS narrator voices filtered by language. parameters: ctx [Context]: context object representing command invocation language [str] (default=''): language to filter by """ # Check if language was provided if not language: prefix = self.prefixes[ctx.guild] # Create a string of all available languages languages = "`, `".join(sorted(supported_languages.keys())) embed = Embed( title=":book: Voice Directory - Language", description=(f":information_source: **Use** `{prefix}list " "language [Language]` **to display available " "voices**"), colour=Colour.blue()) embed.add_field( name="**Available Languages Options:**", value=f"`{languages}`") # Ensure that language is supported elif await language_is_valid(language): language = language.lower() lang_codes = supported_languages[language] field_index = 0 page_number = 1 # Generate embed page embed = Embed( title=( ":book: Voice Directory - Language - " f"{language.capitalize()}"), colour=Colour.blue()) embed.set_footer(text=f"Page #{page_number}") for voice_info in self._voice_filter('lang_code', *lang_codes): # Check if the number of fields exceeds embed page limit if (field_index >= self.MAX_EMBED_FIELDS): field_index = 0 page_number += 1 # Send old embed page await ctx.send(embed=embed) # Generate new embed page embed = Embed( title=( ":book: Voice Directory - Language - " f"{language.capitalize()}"), colour=Colour.blue()) embed.set_footer(text=f"Page #{page_number}") # Add voice to embed embed.add_field( name=f"{voice_info[0]}", value=f"Region: {voice_info[1]}\nGender: {voice_info[2]}") field_index += 1 # Add padding field if needed if field_index > 3 and field_index % 3 == 2: embed.add_field(name="⠀", value="⠀") await ctx.send(embed=embed)
async def quotes(self, ctx: Context) -> None: """Chooses between a list of quotes.""" embed_quote = Embed(title=random.choice(lines), color=Colour.green()) await ctx.send(embed=embed_quote)
async def user(self, ctx, argument=None): if argument is not None: if argument.isdigit(): ctx.author = self.bot.get_user(int(argument)) if ctx.author is None: return await ctx.send( "Sorry Senpai, I can't find anyone with that ID qwq") else: ID = argument[3:] ID = ID[:-1] ctx.author = self.bot.get_user(int(ID)) logging_info(f'Recieved user {ctx.author.name}') ref = dab.collection("users").document(str(ctx.author.id)).get() if ref.exists is False: logging_info(f"User not found") if argument is None: return await ctx.send( "You're not in my database, Senpai! qwq\nYou should use ``>user add`` <w<" ) elif argument is not None: return await ctx.send("That person isn't in my database qwq") username = ref.get("username") scoresaber = ref.get("scoresaber") links_Message = f"[Scoresaber]({scoresaber}) " try: steam = ref.get("steam") links_Message = links_Message + f"| [Steam]({steam}) " except BaseException: True try: twitch = ref.get("twitch") links_Message = links_Message + f"| [Twitch]({twitch}) " except BaseException: True try: youtube = ref.get("youtube") links_Message = links_Message + f"| [Youtube]({youtube}) " except BaseException: True try: twitter = ref.get("twitter") links_Message = links_Message + f"| [Twitter]({twitter}) " except BaseException: True try: reddit = ref.get("reddit") links_Message = links_Message + f"| [Reddit]({reddit}) " except BaseException: True try: hmd = ref.get("hmd") except BaseException: hmd = None try: birthday = ref.get("birthday") except BaseException: birthday = None try: pfp = ref.get("pfp") except BaseException: pfp = None try: status = ref.get("status") except BaseException: status = None # try: # this on for size, Mister try: colourRaw = ref.get("colour") colour = await commands.ColourConverter().convert( ctx, "0x" + colourRaw) embed = Embed(title=username, colour=colour) except BaseException: embed = Embed(title=username, colour=Colour.random()) embed.add_field(name="Links", value=links_Message, inline=False) if hmd is not None: embed.add_field(name="HMD", value=hmd, inline=True) if birthday is not None: embed.add_field(name="Birthday", value=birthday, inline=True) if status is not None: embed.add_field(name="Status", value=status, inline=False) if pfp is not None: embed.set_thumbnail(url=pfp) else: embed.set_thumbnail(url=ctx.author.avatar_url) await ctx.reply(embed=embed) logging_info('Response: user embed\n----------')
def make_embeds(coins, current_prices, author, net_worth): """ This function is used to combine a series of coins into a embed (or more than one if wallet is big) """ embeds = [] num_fields = 0 page = 1 embed = Embed( title=f"{author}'s current Wallet" + "" if page == 1 else f" Page {page}", colour=Colour(0xFF00FF), type="rich", description= '**--------------------------------------------------------------------------------------------------**' ) embed.set_footer(text="Pairs calculated via Binance") for c in coins: # if adding these 3 fields would exceed the allowed amount # make a new embed and save the old one someone where else first_field = True if num_fields + 5 > Constants.FIELD_LIMIT.value: embeds.append(embed.copy()) page += 1 num_fields = 0 embed = Embed( title=f"{author}'s current Wallet" + "" if page == 1 else f" Page {page}", colour=Colour(0xFF00FF), type="rich", description= '**--------------------------------------------------------------------------------------------------**' ) embed.set_footer(text="Pairs calculated via Binance") num_fields += 4 embed.add_field( name=f'Coin/Pair: {c}', value= f"**Current Price**: {'$' + f'{current_prices[c][0]:,}' if current_prices[c][0] is not None else 'Unknown'} **Wallet Value**: ${current_prices[c][1]:,} USDT", inline=False) for row in coins[c]: price, quantity, date = row embed.add_field( name="Buy Price" if first_field else Constants.EMPTY.value, value=price, inline=True) embed.add_field( name="Quantity" if first_field else Constants.EMPTY.value, value=quantity, inline=True) embed.add_field(name="Saved at (UTC Time)" if first_field else Constants.EMPTY.value, value=date, inline=True) embed.add_field(name=Constants.EMPTY.value, value=Constants.EMPTY.value, inline=False) first_field = False # if this statement is true, then we did not save the last embed if num_fields != 0: embeds.append(embed) # Adding the worth up for each price in the footer of the last embed embeds[-1].set_footer( text=f"Net worth of known coins is ${net_worth:,} USDT") return embeds
async def poll_new_posts(self) -> None: """Periodically search for new subreddit posts.""" while True: await asyncio.sleep(RedditConfig.request_delay) for subreddit in RedditConfig.subreddits: # Make a HEAD request to the subreddit head_response = await self.bot.http_session.head( url=f"{self.URL}/{subreddit}/new.rss", headers=self.HEADERS) content_length = head_response.headers["content-length"] # If the content is the same size as before, assume there's no new posts. if content_length == self.prev_lengths.get(subreddit, None): continue self.prev_lengths[subreddit] = content_length # Now we can actually fetch the new data posts = await self.fetch_posts(f"{subreddit}/new") new_posts = [] # Only show new posts if we've checked before. if subreddit in self.last_ids: for post in posts: data = post["data"] # Convert the ID to an integer for easy comparison. int_id = int(data["id"], 36) # If we've already seen this post, finish checking if int_id <= self.last_ids[subreddit]: break embed_data = { "title": textwrap.shorten(data["title"], width=64, placeholder="..."), "text": textwrap.shorten(data["selftext"], width=128, placeholder="..."), "url": self.URL + data["permalink"], "author": data["author"] } new_posts.append(embed_data) self.last_ids[subreddit] = int(posts[0]["data"]["id"], 36) # Send all of the new posts as spicy embeds for data in new_posts: embed = Embed() embed.title = data["title"] embed.url = data["url"] embed.description = data["text"] embed.set_footer( text=f"Posted by u/{data['author']} in {subreddit}") embed.colour = Colour.blurple() await self.reddit_channel.send(embed=embed) log.trace( f"Sent {len(new_posts)} new {subreddit} posts to channel {self.reddit_channel.id}." )
async def warn(self, ctx, member: Member, *, reason: str = ""): """ Warn members. (Staff Only) A user ID can be used instead of mentionning the user. - First warn : nothing happens, a simple warning - Second warn : muted until an the admin who issued the warning decides to unmute the user. - Third warn : kicked - Fourth warn : kicked - Fifth warn : banned """ author = ctx.message.author if member == ctx.message.author: await ctx.send("You cannot warn yourself!") return if self.bot.staff_role in member.roles and self.bot.owner_role not in author.roles: await ctx.send("You cannot warn other staff members!") return elif self.bot.owner_role in member.roles: await ctx.send("💢 I don't have the permission to do that!") return elif ctx.me is member: await ctx.send("I should not warn myself!") return try: with open("database/warns.json", "r") as config: js = load(config) except FileNotFoundError: with open("database/warns.json", "w") as config: config.write('{}') js = {} userid = str(member.id) if userid not in js: amount_of_warns = 1 js[userid] = {"warns": []} else: amount_of_warns = len(js[userid]["warns"]) + 1 member_name = "{}#{}".format(member.name, member.discriminator) timestamp = strftime("%Y-%m-%d %H:%M:%S", localtime()) author_name = "{}#{}".format(author.name, author.discriminator) js[userid]["amount"] = amount_of_warns js[userid]["warns"].append({ "name": member_name, "timestamp": timestamp, "reason": reason, "author": author_name, "author_id": author.id, }) await ctx.send("🚩 I've warned {}. The user now has {} warns." "".format(member, amount_of_warns)) if reason == "": await self.dm(member, "You have been warned in {}.".format(ctx.guild.name)) else: await self.dm( member, "You have been warned in {} for the following reason :\n{}\n" "".format(ctx.guild.name, reason)) emb = Embed(title="Member Warned", colour=Colour.orange()) emb.add_field(name="Member:", value=member, inline=True) emb.add_field(name="Warning Number:", value=amount_of_warns, inline=True) emb.add_field(name="Mod:", value=ctx.message.author, inline=True) if reason == "": reason = "No reason specified." emb.add_field(name="Reason:", value=reason, inline=True) logchannel = self.bot.logs_channel await logchannel.send("", embed=emb) if amount_of_warns == 1: await self.dm( member, "This is your first warning. " "The next warning will automatically mute you.") elif amount_of_warns == 2: await self.dm( member, "This is your second warning, so you've been muted. You will be unmuted " "whenever the admin who warned you decides to unmute you.\nYou will be " "DM'ed when a mod unmutes you.\n**Do not ask mods to unmute you, as " "doing so might extend the duration of the mute**") await self.dm( member, "Your next warn will result in being kicked from the server.") await member.add_roles(self.bot.muted_role) elif amount_of_warns == 3: await self.dm( member, "This is your third warning, so you have been kicked. Please " "note that **the next warn will result in another kick!**") await member.kick(reason="Third warn") elif amount_of_warns == 4: await self.dm( member, "You have been kicked from the server. This is your fourth and " "final warning. **__The next warning will result in an automatic" " permanent ban.__**") await member.kick(reason="Fourth warn") elif amount_of_warns >= 5: await self.dm( member, "You have reached your fifth warning. You are now permanently " "banned from this server.") await member.ban(delete_message_days=0, reason="Fifth warn.") with open("database/warns.json", "w") as f: dump(js, f, sort_keys=True, indent=4, separators=(',', ': '))
async def on_guild_channel_update(self, before: GUILD_CHANNEL, after: GuildChannel) -> None: """Log channel update event to mod log.""" if before.guild.id != GuildConstant.id: return if before.id in self._ignored[Event.guild_channel_update]: self._ignored[Event.guild_channel_update].remove(before.id) return # Two channel updates are sent for a single edit: 1 for topic and 1 for category change. # TODO: remove once support is added for ignoring multiple occurrences for the same channel. help_categories = (Categories.help_available, Categories.help_dormant, Categories.help_in_use) if after.category and after.category.id in help_categories: return diff = DeepDiff(before, after) changes = [] done = [] diff_values = diff.get("values_changed", {}) diff_values.update(diff.get("type_changes", {})) for key, value in diff_values.items(): if not key: # Not sure why, but it happens continue key = key[5:] # Remove "root." prefix if "[" in key: key = key.split("[", 1)[0] if "." in key: key = key.split(".", 1)[0] if key in done or key in CHANNEL_CHANGES_SUPPRESSED: continue if key in CHANNEL_CHANGES_UNSUPPORTED: changes.append(f"**{key.title()}** updated") else: new = value["new_value"] old = value["old_value"] # Discord does not treat consecutive backticks ("``") as an empty inline code block, so the markdown # formatting is broken when `new` and/or `old` are empty values. "None" is used for these cases so # formatting is preserved. changes.append( f"**{key.title()}:** `{old or 'None'}` **→** `{new or 'None'}`" ) done.append(key) if not changes: return message = "" for item in sorted(changes): message += f"{Emojis.bullet} {item}\n" if after.category: message = f"**{after.category}/#{after.name} (`{after.id}`)**\n{message}" else: message = f"**#{after.name}** (`{after.id}`)\n{message}" await self.send_log_message(Icons.hash_blurple, Colour.blurple(), "Channel updated", message)
async def clean_cancel(self, ctx: Context) -> None: """If there is an ongoing cleaning process, attempt to immediately cancel it.""" self.cleaning = False embed = Embed(color=Colour.blurple(), description="Clean interrupted.") await ctx.send(embed=embed, delete_after=10)
async def on_voice_state_update(self, member: discord.Member, before: discord.VoiceState, after: discord.VoiceState) -> None: """Log member voice state changes to the voice log channel.""" if (member.guild.id != GuildConstant.id or (before.channel and before.channel.id in GuildConstant.modlog_blacklist)): return if member.id in self._ignored[Event.voice_state_update]: self._ignored[Event.voice_state_update].remove(member.id) return # Exclude all channel attributes except the name. diff = DeepDiff( before, after, exclude_paths=("root.session_id", "root.afk"), exclude_regex_paths=r"root\.channel\.(?!name)", ) # A type change seems to always take precedent over a value change. Furthermore, it will # include the value change along with the type change anyway. Therefore, it's OK to # "overwrite" values_changed; in practice there will never even be anything to overwrite. diff_values = { **diff.get("values_changed", {}), **diff.get("type_changes", {}) } icon = Icons.voice_state_blue colour = Colour.blurple() changes = [] for attr, values in diff_values.items(): if not attr: # Not sure why, but it happens. continue old = values["old_value"] new = values["new_value"] attr = attr[5:] # Remove "root." prefix. attr = VOICE_STATE_ATTRIBUTES.get( attr, attr.replace("_", " ").capitalize()) changes.append(f"**{attr}:** `{old}` **→** `{new}`") # Set the embed icon and colour depending on which attribute changed. if any(name in attr for name in ("Channel", "deaf", "mute")): if new is None or new is True: # Left a channel or was muted/deafened. icon = Icons.voice_state_red colour = Colours.soft_red elif old is None or old is True: # Joined a channel or was unmuted/undeafened. icon = Icons.voice_state_green colour = Colours.soft_green if not changes: return member_str = escape_markdown(str(member)) message = "\n".join(f"{Emojis.bullet} {item}" for item in sorted(changes)) message = f"**{member_str}** (`{member.id}`)\n{message}" await self.send_log_message( icon_url=icon, colour=colour, title="Voice state updated", text=message, thumbnail=member.avatar_url_as(static_format="png"), channel_id=Channels.voice_log)
async def _clean_messages( self, amount: int, ctx: Context, channels: Iterable[TextChannel], bots_only: bool = False, user: User = None, regex: Optional[str] = None, until_message: Optional[Message] = None, ) -> None: """A helper function that does the actual message cleaning.""" def predicate_bots_only(message: Message) -> bool: """Return True if the message was sent by a bot.""" return message.author.bot def predicate_specific_user(message: Message) -> bool: """Return True if the message was sent by the user provided in the _clean_messages call.""" return message.author == user def predicate_regex(message: Message) -> bool: """Check if the regex provided in _clean_messages matches the message content or any embed attributes.""" content = [message.content] # Add the content for all embed attributes for embed in message.embeds: content.append(embed.title) content.append(embed.description) content.append(embed.footer.text) content.append(embed.author.name) for field in embed.fields: content.append(field.name) content.append(field.value) # Get rid of empty attributes and turn it into a string content = [attr for attr in content if attr] content = "\n".join(content) # Now let's see if there's a regex match if not content: return False else: return bool(re.search(regex.lower(), content.lower())) # Is this an acceptable amount of messages to clean? if amount > CleanMessages.message_limit: embed = Embed( color=Colour(Colours.soft_red), title=random.choice(NEGATIVE_REPLIES), description= f"You cannot clean more than {CleanMessages.message_limit} messages." ) await ctx.send(embed=embed) return # Are we already performing a clean? if self.cleaning: embed = Embed( color=Colour(Colours.soft_red), title=random.choice(NEGATIVE_REPLIES), description= "Please wait for the currently ongoing clean operation to complete." ) await ctx.send(embed=embed) return # Set up the correct predicate if bots_only: predicate = predicate_bots_only # Delete messages from bots elif user: predicate = predicate_specific_user # Delete messages from specific user elif regex: predicate = predicate_regex # Delete messages that match regex else: predicate = None # Delete all messages # Default to using the invoking context's channel if not channels: channels = [ctx.channel] # Delete the invocation first self.mod_log.ignore(Event.message_delete, ctx.message.id) try: await ctx.message.delete() except errors.NotFound: # Invocation message has already been deleted log.info( "Tried to delete invocation message, but it was already deleted." ) messages = [] message_ids = [] self.cleaning = True # Find the IDs of the messages to delete. IDs are needed in order to ignore mod log events. for channel in channels: async for message in channel.history(limit=amount): # If at any point the cancel command is invoked, we should stop. if not self.cleaning: return # If we are looking for specific message. if until_message: # we could use ID's here however in case if the message we are looking for gets deleted, # we won't have a way to figure that out thus checking for datetime should be more reliable if message.created_at < until_message.created_at: # means we have found the message until which we were supposed to be deleting. break # Since we will be using `delete_messages` method of a TextChannel and we need message objects to # use it as well as to send logs we will start appending messages here instead adding them from # purge. messages.append(message) # If the message passes predicate, let's save it. if predicate is None or predicate(message): message_ids.append(message.id) self.cleaning = False # Now let's delete the actual messages with purge. self.mod_log.ignore(Event.message_delete, *message_ids) for channel in channels: if until_message: for i in range(0, len(messages), 100): # while purge automatically handles the amount of messages # delete_messages only allows for up to 100 messages at once # thus we need to paginate the amount to always be <= 100 await channel.delete_messages(messages[i:i + 100]) else: messages += await channel.purge(limit=amount, check=predicate) # Reverse the list to restore chronological order if messages: messages = reversed(messages) log_url = await self.mod_log.upload_log(messages, ctx.author.id) else: # Can't build an embed, nothing to clean! embed = Embed(color=Colour(Colours.soft_red), description="No matching messages could be found.") await ctx.send(embed=embed, delete_after=10) return # Build the embed and send it target_channels = ", ".join(channel.mention for channel in channels) message = ( f"**{len(message_ids)}** messages deleted in {target_channels} by " f"{ctx.author.mention}\n\n" f"A log of the deleted messages can be found [here]({log_url}).") await self.mod_log.send_log_message( icon_url=Icons.message_bulk_delete, colour=Colour(Colours.soft_red), title="Bulk message delete", text=message, channel_id=Channels.mod_log, )
def get_item(name): """Returns a dictionary containing an item's info, if no exact match was found, it returns a list of suggestions. The dictionary has the following keys: name, look_text, npcs_sold*, value_sell, npcs_bought*, value_buy. *npcs_sold and npcs_bought are list, each element is a dictionary with the keys: name, city.""" # Reading item database c = tibiaDatabase.cursor() # Search query c.execute( "SELECT * FROM Items WHERE title LIKE ? ORDER BY LENGTH(title) ASC LIMIT 15", ("%" + name + "%", )) result = c.fetchall() if len(result) == 0: return None elif result[0]["title"].lower() == name.lower() or len(result) == 1: item = result[0] else: return [x['title'] for x in result] try: # Checking if item exists if item is not None: # Checking NPCs that buy the item c.execute( "SELECT NPCs.title, city, value " "FROM Items, SellItems, NPCs " "WHERE Items.name LIKE ? AND SellItems.itemid = Items.id AND NPCs.id = vendorid " "ORDER BY value DESC", (name, )) npcs = [] value_sell = None for npc in c: name = npc["title"] city = npc["city"].title() if value_sell is None: value_sell = npc["value"] elif npc["value"] != value_sell: break # Replacing cities for special npcs and adding colors if name == 'Alesar' or name == 'Yaman': city = 'Green Djinn\'s Fortress' item["color"] = Colour.green() elif name == 'Nah\'Bob' or name == 'Haroun': city = 'Blue Djinn\'s Fortress' item["color"] = Colour.blue() elif name == 'Rashid': city = get_rashid_city() item["color"] = Colour(0xF0E916) elif name == 'Yasir': city = 'his boat' elif name == 'Briasol': item["color"] = Colour(0xA958C4) npcs.append({"name": name, "city": city}) item['npcs_sold'] = npcs item['value_sell'] = value_sell # Checking NPCs that sell the item c.execute( "SELECT NPCs.title, city, value " "FROM Items, BuyItems, NPCs " "WHERE Items.name LIKE ? AND BuyItems.itemid = Items.id AND NPCs.id = vendorid " "ORDER BY value ASC", (name, )) npcs = [] value_buy = None for npc in c: name = npc["title"] city = npc["city"].title() if value_buy is None: value_buy = npc["value"] elif npc["value"] != value_buy: break # Replacing cities for special npcs if name == 'Alesar' or name == 'Yaman': city = 'Green Djinn\'s Fortress' elif name == 'Nah\'Bob' or name == 'Haroun': city = 'Blue Djinn\'s Fortress' elif name == 'Rashid': offset = get_tibia_time_zone() - get_local_timezone() # Server save is at 10am, so in tibia a new day starts at that hour tibia_time = datetime.now() + timedelta(hours=offset - 10) city = [ "Svargrond", "Liberty Bay", "Port Hope", "Ankrahmun", "Darashia", "Edron", "Carlin" ][tibia_time.weekday()] elif name == 'Yasir': city = 'his boat' npcs.append({"name": name, "city": city}) item['npcs_bought'] = npcs item['value_buy'] = value_buy # Get creatures that drop it c.execute( "SELECT Creatures.title as name, CreatureDrops.percentage " "FROM CreatureDrops, Creatures " "WHERE CreatureDrops.creatureid = Creatures.id AND CreatureDrops.itemid = ? " "ORDER BY percentage DESC", (item["id"], )) item["dropped_by"] = c.fetchall() # Checking quest rewards: c.execute( "SELECT Quests.title FROM Quests, QuestRewards " "WHERE Quests.id = QuestRewards.questid and itemid = ?", (item["id"], )) quests = c.fetchall() item["quests"] = list() for quest in quests: item["quests"].append(quest["title"]) return item finally: c.close() return
async def on_member_update(self, before: discord.Member, after: discord.Member) -> None: """Log member update event to user log.""" if before.guild.id != GuildConstant.id: return if before.id in self._ignored[Event.member_update]: self._ignored[Event.member_update].remove(before.id) return diff = DeepDiff(before, after) changes = [] done = [] diff_values = {} diff_values.update(diff.get("values_changed", {})) diff_values.update(diff.get("type_changes", {})) diff_values.update(diff.get("iterable_item_removed", {})) diff_values.update(diff.get("iterable_item_added", {})) diff_user = DeepDiff(before._user, after._user) diff_values.update(diff_user.get("values_changed", {})) diff_values.update(diff_user.get("type_changes", {})) diff_values.update(diff_user.get("iterable_item_removed", {})) diff_values.update(diff_user.get("iterable_item_added", {})) for key, value in diff_values.items(): if not key: # Not sure why, but it happens continue key = key[5:] # Remove "root." prefix if "[" in key: key = key.split("[", 1)[0] if "." in key: key = key.split(".", 1)[0] if key in done or key in MEMBER_CHANGES_SUPPRESSED: continue if key == "_roles": new_roles = after.roles old_roles = before.roles for role in old_roles: if role not in new_roles: changes.append( f"**Role removed:** {role.name} (`{role.id}`)") for role in new_roles: if role not in old_roles: changes.append( f"**Role added:** {role.name} (`{role.id}`)") else: new = value.get("new_value") old = value.get("old_value") if new and old: changes.append(f"**{key.title()}:** `{old}` **→** `{new}`") done.append(key) if before.name != after.name: changes.append( f"**Username:** `{before.name}` **→** `{after.name}`") if before.discriminator != after.discriminator: changes.append( f"**Discriminator:** `{before.discriminator}` **→** `{after.discriminator}`" ) if before.display_name != after.display_name: changes.append( f"**Display name:** `{before.display_name}` **→** `{after.display_name}`" ) if not changes: return message = "" for item in sorted(changes): message += f"{Emojis.bullet} {item}\n" message = f"**{after}** (`{after.id}`)\n{message}" await self.send_log_message( Icons.user_update, Colour.blurple(), "Member updated", message, thumbnail=after.avatar_url_as(static_format="png"), channel_id=Channels.user_log)
async def voice_verify(self, ctx: Context, *_) -> None: """ Apply to be able to use voice within the Discord server. In order to use voice you must meet all three of the following criteria: - You must have over a certain number of messages within the Discord server - You must have accepted our rules over a certain number of days ago - You must not be actively banned from using our voice channels - You must have been active for over a certain number of 10-minute blocks """ await self._delete_ping( ctx.author.id ) # If user has received a ping in voice_verification, delete the message try: data = await self.bot.api_client.get( f"bot/users/{ctx.author.id}/metricity_data") except ResponseCodeError as e: if e.status == 404: embed = discord.Embed( title="Not found", description= ("We were unable to find user data for you. " "Please try again shortly, " "if this problem persists please contact the server staff through Modmail." ), color=Colour.red()) log.info( f"Unable to find Metricity data about {ctx.author} ({ctx.author.id})" ) else: embed = discord.Embed( title="Unexpected response", description= ("We encountered an error while attempting to find data for your user. " "Please try again and let us know if the problem persists." ), color=Colour.red()) log.warning( f"Got response code {e.status} while trying to get {ctx.author.id} Metricity data." ) try: await ctx.author.send(embed=embed) except discord.Forbidden: log.info( "Could not send user DM. Sending in voice-verify channel and scheduling delete." ) await ctx.send(embed=embed) return checks = { "joined_at": (ctx.author.joined_at > arrow.utcnow() - timedelta(days=GateConf.minimum_days_member)), "total_messages": data["total_messages"] < GateConf.minimum_messages, "voice_banned": data["voice_banned"], "activity_blocks": data["activity_blocks"] < GateConf.minimum_activity_blocks, } failed = any(checks.values()) failed_reasons = [ MESSAGE_FIELD_MAP[key] for key, value in checks.items() if value is True ] [ self.bot.stats.incr(f"voice_gate.failed.{key}") for key, value in checks.items() if value is True ] if failed: embed = discord.Embed( title="Voice Gate failed", description=FAILED_MESSAGE.format(reasons="\n".join( f'• You {reason}.' for reason in failed_reasons)), color=Colour.red()) try: await ctx.author.send(embed=embed) await ctx.send(f"{ctx.author}, please check your DMs.") except discord.Forbidden: await ctx.channel.send(ctx.author.mention, embed=embed) return self.mod_log.ignore(Event.member_update, ctx.author.id) embed = discord.Embed( title="Voice gate passed", description= "You have been granted permission to use voice channels in Python Discord.", color=Colour.green()) if ctx.author.voice: embed.description += "\n\nPlease reconnect to your voice channel to be granted your new permissions." try: await ctx.author.send(embed=embed) await ctx.send(f"{ctx.author}, please check your DMs.") except discord.Forbidden: await ctx.channel.send(ctx.author.mention, embed=embed) # wait a little bit so those who don't get DMs see the response in-channel before losing perms to see it. await asyncio.sleep(3) await ctx.author.add_roles(discord.Object(Roles.voice_verified), reason="Voice Gate passed") self.bot.stats.incr("voice_gate.passed")
async def roll(self, ctx: commands.Context, *, roll: str = 'D'): parts = [] if '+' in roll or '-' in roll: for part in roll.split('+'): if not part.strip(): continue if '-' in roll: for i in range(len(part.split('-'))): parts_ = part.split('-') if not parts_[i].strip(): continue part_dict = { 'raw': parts_[i].strip().upper(), 'sign': '-', 'process': None, 'result': None } if i: part_dict['sign'] = '-' else: part_dict['sign'] = '+' parts.append(part_dict) else: parts.append({ 'raw': part.strip().upper(), 'sign': '+', 'process': None, 'result': None }) else: parts.append({ 'raw': roll.strip().upper(), 'sign': '+', 'process': None, 'result': None }) for part in parts: part['raw'] = part['raw'].replace(' ', '', part['raw'].count(' ')) if 'D' in part['raw']: raws = part['raw'].split('D') try: dices = int(raws[0].strip() if raws[0] else 1) pips = int((raws[1].strip() if raws[1] != '%' else '100' ) if raws[1] else 6) except ValueError: await ctx.send('주사위 수와 눈을 정확한 숫자로 입력해주세요.') return if dices <= 0: await ctx.send('주사위의 수는 한 개 이상이어야 합니다.') return if pips <= 0: await ctx.send('주사위의 눈은 한 개 이상이어야 합니다.') return throwns = [] for i in range(dices): throwns.append(randint(1, pips)) part['process'] = str(throwns) part['result'] = sum(throwns) * (-1 if part['sign'] == '-' else 1) else: part['process'] = part['raw'] try: part['result'] = int( part['raw']) * (-1 if part['sign'] == '-' else 1) except ValueError: await ctx.send('더하는 값을 정확한 숫자로 입력해주세요.') return raw_description = '' process_description = '' for part in parts: raw_description += f'{part["sign"]} {part["raw"]} ' process_description += f'{part["sign"]} {part["process"]} ' description = '**' + raw_description + '**' description += '\n= ' + process_description description += '\n= ***__' + str(sum(part['result'] for part in parts)) + '__***' embed = Embed(title=':game_die: 주사위 굴림', description=description, colour=Colour.blurple()) embed.set_author(name=ctx.author, icon_url=ctx.author.avatar_url) embed.set_thumbnail(url=self.client.user.avatar_url) await ctx.send(ctx.author.mention, embed=embed)
async def getserver(self, ctx, serverip: str): """Get infos about a gameserver""" while serverip.find(":") == -1: print("No port specified using 27015\n") serverip += ":27015" serverc = serverip.split(":") if not serverc[0][0].isdigit(): try: ip = gethostbyname_ex(serverc[0])[2][0] except: await self.bot.say("The specified domain is not valid") return servercheck = ip serverc = [str(ip), int(serverc[1])] else: servercheck = serverc[0] serverc = [str(serverc[0]), int(serverc[1])] serverc = tuple(serverc) if not self.validate_ip(str(servercheck)): await send_cmd_help(ctx) return try: server = valve.source.a2s.ServerQuerier(serverc) try: info = server.get_info( ) # workaround for old version ADD GIT SUPPORT 26 except: info = server.info() except valve.source.a2s.NoResponseError: await self.bot.say( "Could not fetch Server or the Server is not on the Steam masterlist" ) return except: await self.bot.say("Unkown Error has occured") return map = info.values['map'] if map.lower().startswith("workshop"): link = "https://steamcommunity.com/sharedfiles/filedetails/?id={}".format( map.split("/")[1]) map = "{} [(Workshop map)]({})".format(map.split("/")[2], link) game = info.values['folder'] gamemode = info.values['game'] servername = info.values['server_name'].strip() playernumber = str(info.values['player_count'] - info.values['bot_count']) botnumber = str(info.values['bot_count']) maxplayers = str(info.values['max_players']) if int(info.values['vac_enabled']): vac = "enabled" else: vac = "disabled" os = str(info.values['platform']) em = Embed(colour=Colour.green()) em.add_field(name="Game", value=game) em.add_field(name="Gamemode", value=gamemode) em.add_field(name="servername", value=servername, inline=False) em.add_field(name="IP", value=serverc[0]) em.add_field(name="Operating System", value=os) em.add_field(name="VAC", value=vac) if botnumber != '0': if botnumber == "1": em.add_field(name="Playernumber", value="{}/{}\n{} Bot".format( playernumber, maxplayers, botnumber)) else: em.add_field(name="Playernumber", value="{}/{}\n{} Bots".format( playernumber, maxplayers, botnumber)) else: em.add_field(name="Playernumber", value="{}/{}\n".format(playernumber, maxplayers)) em.add_field(name="Map", value=map, inline=False) em.add_field( name=u"\u2063", value= "[Connect](steam://connect/{})\n(starting the game over this link may result in lag)" .format(serverip), inline=False) await self.bot.say(embed=em)
async def update_status(get_embed=False): global first_seen, last_seen global server_sec1, sec1_online, sec1_motd, sec1_players, sec1_max, sec1_version global server_sec2, sec2_online, sec2_motd, sec2_players, sec2_max, sec2_version embed = Embed( #title="Szkolny.eu Minecraft", color=Colour.from_rgb(0x21, 0x96, 0xf3), url=HOMEPAGE_URL ) embed.set_footer(text=f'Aktualizacja: {datetime.now().strftime(DATE_FORMAT)}') try: await server_status(embed) except Exception as e: await server_disconnected(embed, e) if SEC1_IP: if sec1_online: uptime = datetime.now() - sec1_online uptime = str(uptime).split('.')[0] embed.add_field( name=SEC1_NAME, value=f':white_check_mark: {sec1_motd}\n' f'`{sec1_players}/{sec1_max} graczy, {sec1_version}, {uptime}`\n' f'{SEC1_DESCRIPTION}', inline=False ) else: embed.add_field( name=SEC1_NAME, value=f':x: {sec1_motd}', inline=False ) if SEC2_IP: if sec2_online: uptime = datetime.now() - sec2_online uptime = str(uptime).split('.')[0] embed.add_field( name=SEC2_NAME, value=f':white_check_mark: {sec2_motd}\n' f'`{sec2_players}/{sec2_max} graczy, {sec2_version}, {uptime}`\n' f'{SEC2_DESCRIPTION}', inline=False ) else: embed.add_field( name=SEC2_NAME, value=f':x: {sec2_motd}', inline=False ) global message if message and not get_embed: await message.edit(embed=embed, content="") elif get_embed: return embed
async def create_blank_role(self, ctx, role): await ctx.guild.create_role(name=role, colour=Colour.orange(), mentionable=True, reason=f"Blank role created by GAF Bot, invoked by {ctx.author}") await ctx.send("Created blank role :pencil:")
async def mc(ctx, arg): await ctx.message.delete() if arg == "status": return db = mysql.connector.connect( host=MYSQL_HOST, user=MYSQL_USER, passwd=MYSQL_PASSWORD ) arg = arg.split() if len(arg) > 1: arg = arg[1] else: arg = '' # global message # if arg == "init" and not message: # embed = await update_status(get_embed=True) # message = await ctx.send(embed=embed) # return embed = Embed( title="Szkolny.eu Minecraft", color=Colour.from_rgb(0x21, 0x96, 0xf3), url=HOMEPAGE_URL ) embed.set_thumbnail(url=EMBED_IMAGE_URL) embed.description = \ 'Użycie:\n' \ '`/mc <nickname>` - Dodaj swój nickname do whitelisty\n' # \ # '`/mc status` - Wyświetl status serwera\n' if arg and arg != 'status': nickname = arg discord_id = ctx.author.id discord_tag = f'{ctx.author.name}#{ctx.author.discriminator}' cursor = db.cursor(dictionary=True) embed.description = f"Dodano gracza {nickname} do whitelisty." cursor.execute('SELECT * FROM minecraft.whitelist WHERE name = %s OR discordId = %s', (nickname, discord_id)) row = cursor.fetchall() if len(row) > 0: row = row[0] if row: if row['name'] == nickname and row['discordId'] != discord_id: embed.description = f"Gracz {nickname} został już dodany przez `{row['discordTag']}`." msg = await ctx.send(embed=embed) await msg.delete(delay=5) return if row['name'] != nickname: # and row['discordId'] == discord_id: embed.description = f"Dodałeś już gracza {row['name']}, zostanie on zastąpiony graczem {nickname}." try: cursor.execute( 'REPLACE INTO minecraft.whitelist (name, discordId, discordTag) VALUES (%s, %s, %s)', (nickname, discord_id, discord_tag) ) db.commit() except mysql.connector.errors.IntegrityError: embed.description = f"To konto Discord ma już gracza na serwerze." msg = await ctx.send(embed=embed) await msg.delete(delay=5)