async def requirerole(self, ctx: commands.Context, *roles: RoleTuple): """Require one of any specific roles to use the bot in the current guild To require a member to __not__ have one or more roles, you can use `~` before the role name to treat it as a blacklisted role. If a role name has `~` at the start of it's name, you can escape it with a backslash (`\`) character. Blacklisted roles override any possible whitelisted roles a member may have. Role names are case sensitive. If a role has spaces in it's name, wrap it in quotes. Passing no roles removes any currently set role requirements. The guild owner and members with the Administrator permission always bypass these requirements, regardless of roles.""" seen = SeenSet() roles = tuple( (k, v) for k, v in roles if seen.mark_seen(k)) # type: Tuple[Tuple[discord.Role, bool]] whitelist = tuple(r for r, v in roles if v) # type: Tuple[discord.Role] blacklist = tuple(r for r, v in roles if not v) # type: Tuple[discord.Role] if ctx.guild.default_role in roles: await ctx.send( warning( _("I can't set a role requirement with the guild's default role - " "if you'd like to clear your current role requirements, " "you can execute this command with no arguments to do so." ))) return await self.config.guild(ctx.guild).roles.set({ "whitelist": [x.id for x in whitelist], "blacklist": [x.id for x in blacklist] }) if not roles: await ctx.send(tick(_("Cleared currently set role requirements."))) return whitelist = ", ".join( escape(str(x), mass_mentions=True, formatting=True) for x in whitelist) blacklist = ", ".join( escape(str(x), mass_mentions=True, formatting=True) for x in blacklist) msg = _( "A member will now need to pass the following checks to use my commands:\n\n" ) if whitelist: msg += _("**Any of the following roles:**\n{roles}").format( roles=whitelist) if whitelist and blacklist: msg += "\n\n" if blacklist: msg += _("**None of the following roles:**\n{roles}").format( roles=blacklist) await ctx.send(tick(msg))
async def game_outcomes(self, guild, players, target): success_rate = await self.calculate_success(guild, target) crew = await self.config.guild(guild).Crew() config = await self.get_guild_settings(guild) good_out, bad_out = self.get_theme(config) results = [] for player in players: chance = random.randint(1, 100) if chance <= success_rate: good_thing = random.choice(good_out) good_out.remove(good_thing) crew[player.id] = { "Name": escape(player.display_name, formatting=True), "Bonus": good_thing[1] } await self.config.guild(guild).Crew.set(crew) await self.add_member_spree(player) results.append(good_thing[0].format( escape(player.display_name, formatting=True))) else: bad_thing = random.choice(bad_out) dropout_msg = (bad_thing[0] + "```\n{0} dropped out of the game.```").format( escape(player.display_name, formatting=True)) await self.failure_handler(player, bad_thing[1]) del crew[str(player.id)] await self.config.guild(guild).Crew.set(crew) bad_out.remove(bad_thing) results.append(dropout_msg) return results
async def _clear_heist(self, ctx, user: discord.Member): """Clears a member of jail and death statuses.""" author = ctx.message.author await self.thief.member_clear(user) await ctx.send("```{} administratively cleared {}```".format( escape(author.display_name, formatting=True), escape(user.display_name, formatting=True)))
async def check_streams(self): for stream in self.streams: with contextlib.suppress(Exception): try: if stream.__class__.__name__ == "TwitchStream": await self.maybe_renew_twitch_bearer_token() embed, is_rerun = await stream.is_online() else: embed = await stream.is_online() is_rerun = False except OfflineStream: if not stream._messages_cache: continue for message in stream._messages_cache: with contextlib.suppress(Exception): autodelete = await self.db.guild(message.guild).autodelete() if autodelete: await message.delete() stream._messages_cache.clear() await self.save_streams() else: if stream._messages_cache: continue for channel_id in stream.channels: channel = self.bot.get_channel(channel_id) if not channel: continue ignore_reruns = await self.db.guild(channel.guild).ignore_reruns() if ignore_reruns and is_rerun: continue mention_str, edited_roles = await self._get_mention_str(channel.guild) if mention_str: alert_msg = await self.db.guild(channel.guild).live_message_mention() if alert_msg: content = alert_msg.format(mention=mention_str, stream=stream) else: content = _("{mention}, {stream} is live!").format( mention=mention_str, stream=escape( str(stream.name), mass_mentions=True, formatting=True ), ) else: alert_msg = await self.db.guild(channel.guild).live_message_nomention() if alert_msg: content = alert_msg.format(stream=stream) else: content = _("{stream} is live!").format( stream=escape( str(stream.name), mass_mentions=True, formatting=True ) ) m = await channel.send(content, embed=embed) stream._messages_cache.append(m) if edited_roles: for role in edited_roles: await role.edit(mentionable=False) await self.save_streams()
async def _play_heist(self, ctx): """This begins a Heist""" author = ctx.message.author guild = ctx.guild config = await self.thief.get_guild_settings(guild) theme = await self.thief.get_guild_theme(guild) crew = await self.thief.config.guild(guild).Crew() await self.thief.check_server_settings(guild) await self.thief.check_member_settings(author) cost = config["Cost"] wait_time = config["Wait"] prefix = ctx.prefix # Theme Variables t_crew = theme["Crew"] t_heist = theme["Heist"] t_vault = theme["Vault"] outcome, msg = await self.thief.requirement_check(prefix, author, cost) if outcome == "Failed": return await ctx.send(msg) if not config["Planned"]: await bank.withdraw_credits(author, cost) config["Planned"] = True await self.thief.config.guild(guild).Config.set(config) crew = await self.thief.add_crew_member(author) await ctx.send( "A {4} is being planned by {0}\nThe {4} " "will begin in {1} seconds. Type {2}heist play to join their " "{3}.".format( escape(author.display_name, formatting=True), wait_time, ctx.prefix, t_crew, t_heist, )) await asyncio.sleep(wait_time) crew = await self.thief.config.guild(guild).Crew() if len(crew) <= 1: await ctx.send( "You tried to rally a {}, but no one wanted to follow you. The " "{} has been cancelled.".format(t_crew, t_heist)) await self.thief.reset_heist(guild) else: await self.heist_game(ctx, guild, t_heist, t_crew, t_vault) else: await bank.withdraw_credits(author, cost) crew = await self.thief.add_crew_member(author) crew_size = len(crew) await ctx.send("{0} has joined the {2}.\nThe {2} now has {1} " "members.".format( escape(author.display_name, formatting=True), crew_size, t_crew))
async def someone(self, ctx, *, text: str = None): """Help I've fallen and I need @someone. Discord 2018 April Fools.""" smilies = [ "¯\\_(ツ)_/¯", "(∩ ͡° ͜ʖ ͡°)⊃━☆゚. o ・ 。゚", "(∩ ͡° ͜ʖ ͡°)⊃━✿✿✿✿✿✿", "༼ つ ◕_◕ ༽つ", "(◕‿◕✿)", "(⁄ ⁄•⁄ω⁄•⁄ ⁄)", "(╯°□°)╯︵ ┻━┻", "ಠ_ಠ", "¯\\(°_o)/¯", "(✿ ͡◕ ᴗ◕)つ━━✫・o。", "ヽ༼ ಠ益ಠ ༽ノ", ] smile = random.choice(smilies) member = random.choice(ctx.channel.members) await ctx.send( "**@someone** {} ***{}*** {}".format( smile, chat.escape(member.display_name, mass_mentions=True), chat.escape(text, mass_mentions=True) if text else "", ) )
async def channels(self, ctx, *, server: int = None): """Get all channels on server""" if server is None: server = ctx.guild else: server = discord.utils.get(self.bot.guilds, id=server) if server is None: await ctx.send("Failed to get server with provided ID") return categories = "\n".join( [chat.escape(x.name) for x in server.categories]) or "No categories" text_channels = "\n".join( [chat.escape(x.name) for x in server.text_channels]) or "No text channels" voice_channels = "\n".join( [chat.escape(x.name) for x in server.voice_channels]) or "No voice channels" em = discord.Embed(title="Channels list", color=await ctx.embed_color()) em.add_field(name="Categories:", value=categories, inline=False) em.add_field(name="Text channels:", value=text_channels, inline=False) em.add_field(name="Voice channels:", value=voice_channels, inline=False) em.set_footer( text="Total count of channels: {} • " "Categories: {} • " "Text Channels: {} • " "Voice Channels: {}".format( len(server.channels), len(server.categories), len(server.text_channels), len(server.voice_channels))) await ctx.send(embed=em)
async def send_to(self, ctx: Context, content=None): if await ctx.embed_requested(): return await ctx.send(content=content, embed=self) content = str(content) if content is not None else None if content: content = [content, ""] else: content = [] next_break = False title = self._("title") if title: content.append(CF.bold(title)) next_break = True name = self._("author.name") if name: content.append(CF.italics(name)) next_break = True url = self._("thumbnail.url") if url and not url.startswith("attachment://"): content.append(f"<{url}>") next_break = True description = self._("description") if description: content.append(CF.box(CF.escape(description, formatting=True))) next_break = False if next_break: content.append("") next_break = False for i in range(len(self.fields)): inline, name, value = ( self._("fields", i, "inline"), self._("fields", i, "name"), self._("fields", i, "value"), ) if not inline or len(name) + len( value) > 78 or "\n" in name or "\n" in value: content.append(name) content.append(CF.box(CF.escape(value, formatting=True))) next_break = False else: content.append(f"{name}: {value}") next_break = True if next_break: content.append("") next_break = False url = self._("image.url") if url and not url.startswith("attachment://"): content.append(f"<{url}>") url = self._("video.url") if url and not url.startswith("attachment://"): content.append(f"<{url}>") text, timestamp = self._("footer.text"), self._("timestamp") if text and timestamp: content.append(f"{text} | {timestamp}") elif text: content.append(text) elif timestamp: content.append(f"{timestamp} UTC") content = list(CF.pagify("\n".join(map(str, content)), shorten_by=0)) return await ctx.send_interactive(content)
async def _add_remove(self, ctx: commands.Context, role: discord.Role, *, rm: bool = False): if role.is_default(): raise commands.BadArgument( "cannot make a server's default role mentionable") async with self.config.guild(ctx.guild).roles() as roles: if rm is False: if role.id in roles: await ctx.send( warning(_("That role is already mentionable"))) return roles.append(role.id) else: if role.id not in roles: await ctx.send( warning(_("That role is not currently mentionable"))) return roles.remove(role.id) await ctx.send( escape( tick( _("`{}` is now allowed to be mentioned").format(role. name)), mass_mentions=True, ) if rm is False else escape( tick( _("`{}` is no longer allowed to be mentioned"). format(role.name)), mass_mentions=True, ))
async def uinfo(self, ctx, user: discord.Member = None): """Shows user information. Defaults to author.""" if user is None: user = ctx.author with sps(Exception): caller = inspect.currentframe().f_back.f_code.co_name try: roles = [r for r in user.roles if r.name != "@everyone"] _roles = [roles[0].name,] + [f'{r.name:>{len(r.name)+17}}' for r in roles[1:]] except IndexError: # if there are no roles then roles[0] will raise the IndexError here _roles = ["None"] seen = str(len(set([member.guild.name for member in self.bot.get_all_members() if member.id == user.id]))) load = "```\nLoading user info...```" waiting = await ctx.send(load) data = "```ini\n" data += "[Name]: {}\n".format(cf.escape(str(user))) data += "[ID]: {}\n".format(user.id) data += "[Status]: {}\n".format(user.status) data += "[Servers]: {} shared\n".format(seen) if actplay := discord.utils.get(user.activities, type=discord.ActivityType.playing): data += "[Playing]: {}\n".format(cf.escape(str(actplay.name)))
async def _bailout_heist(self, ctx, user: discord.Member = None): """Specify who you want to pay for release. Defaults to you.""" author = ctx.message.author theme = await self.thief.get_guild_theme(ctx.guild) t_bail = theme["Bail"] t_sentence = theme["Sentence"] if user is None: player = author else: player = user if await self.thief.get_member_status(player) != "Apprehended": return await ctx.send("{} is not in jail.".format( escape(player.display_name, formatting=True))) cost = await self.thief.get_member_bailcost(player) if not await bank.get_balance(player) >= cost: await ctx.send( "You do not have enough to afford the {} amount.".format( t_bail)) return if player.id == author.id: msg = ( "Do you want to make a {0} amount? It will cost {1} credits. If you are " "caught again, your next {2} and {0} amount will triple. " "Do you still wish to pay the {0} amount?".format( t_bail, cost, t_sentence)) else: msg = ( "You are about pay a {2} amount for {0} and it will cost you {1} credits. " "Are you sure you wish to pay {1} for {0}?".format( escape(player.display_name, formatting=True), cost, t_bail)) await ctx.send(msg) try: response = await self.bot.wait_for( "message", timeout=15, check=lambda x: x.author == author) except asyncio.TimeoutError: await ctx.send("You took too long. canceling transaction.") return if "yes" in response.content.lower(): msg = ( "Congratulations {}, you are free! Enjoy your freedom while it " "lasts...".format(escape(player.display_name, formatting=True))) await bank.withdraw_credits(author, cost) await self.thief.set_member_free(author) await self.thief.set_member_oob(author, False) elif "no" in response.content.lower(): msg = "Canceling transaction." else: msg = "Incorrect response, canceling transaction." await ctx.send(msg)
async def uinfo(self, ctx, *, member: discord.Member = None): """Information on a user""" if member is None: member = ctx.message.author em = discord.Embed( title=chat.escape(str(member), formatting=True), color=member.color.value and member.color or discord.Embed.Empty, ) if member.nick: em.add_field(name=_("Nickname"), value=member.nick) else: em.add_field(name=_("Name"), value=member.name) em.add_field( name=_("Client"), value="📱: {}\n" "🖥: {}\n" "🌎: {}".format( str(member.mobile_status).capitalize(), str(member.desktop_status).capitalize(), str(member.web_status).capitalize(), ), ) em.add_field(name=_("Joined server"), value=member.joined_at.strftime(self.TIME_FORMAT)) em.add_field(name="ID", value=member.id) em.add_field( name=_("Exists since"), value=member.created_at.strftime(self.TIME_FORMAT), ) if member.color.value: em.add_field(name=_("Color"), value=member.colour) if member.premium_since: em.add_field( name=_("Boosted server"), value=member.premium_since.strftime(self.TIME_FORMAT), ) em.add_field(name=_("Bot?"), value=bool_emojify(member.bot)) em.add_field(name=_("System?"), value=bool_emojify(member.system)) em.add_field( name=_("Server permissions"), value="[{0}](https://fixator10.ru/permissions-calculator/?v={0})". format(member.guild_permissions.value), ) if member.voice: em.add_field(name=_("In voice channel"), value=member.voice.channel.mention) em.add_field( name=_("Mention"), value=f"{member.mention}\n{chat.inline(member.mention)}", inline=False, ) if roles := [ role.name for role in member.roles if not role.is_default() ]: em.add_field( name=_("Roles"), value=chat.escape("\n".join(roles), formatting=True), inline=False, )
async def emoji_embed( ctx, emoji: Union[discord.Emoji, discord.PartialEmoji]) -> discord.Embed: """Make embed with info about emoji""" em = discord.Embed( title=isinstance(emoji, str) and "\n".join( map( lambda c: unicodedata.name( c, _("[Unable to resolve unicode name]")), emoji)) or chat.escape(emoji.name, formatting=True), color=await ctx.embed_color(), ) if isinstance(emoji, str): # em.add_field(name=_("Unicode emoji"), value="✅") em.add_field( name=_("Unicode character"), value="\n".join( f"\\{c}" if c not in NON_ESCAPABLE_CHARACTERS else c for c in emoji), ) em.add_field( name=_("Unicode category"), value="\n".join(unicodedata.category(c) for c in emoji), ) em.set_image(url=await get_twemoji(emoji)) if not isinstance(emoji, str): em.add_field(name=_("ID"), value=emoji.id) em.add_field(name=_("Animated"), value=bool_emojify(emoji.animated)) em.set_image(url=emoji.url) if isinstance(emoji, discord.Emoji): em.add_field( name=_("Exists since"), value=emoji.created_at.strftime(ctx.cog.TIME_FORMAT), ) em.add_field(name=_('":" required'), value=bool_emojify(emoji.require_colons)) em.add_field(name=_("Managed"), value=bool_emojify(emoji.managed)) em.add_field(name=_("Server"), value=emoji.guild) em.add_field(name=_("Available"), value=bool_emojify(emoji.available)) em.add_field(name=_("Usable by bot"), value=bool_emojify(emoji.is_usable())) if emoji.roles: em.add_field( name=_("Roles"), value=chat.escape("\n".join(x.name for x in emoji.roles), formatting=True), inline=False, ) elif isinstance(emoji, discord.PartialEmoji): em.add_field( name=_("Exists since"), value=emoji.created_at.strftime(ctx.cog.TIME_FORMAT), ) em.add_field(name=_("Custom emoji"), value=bool_emojify(emoji.is_custom_emoji())) # em.add_field( # name=_("Unicode emoji"), value=bool_emojify(emoji.is_unicode_emoji()) # ) return em
async def check_clips(self): log.debug("Checking streamers for clips") for stream in self.streams: log.debug( f"Checking for new {stream.__class__.__name__ } clips from {stream.name}" ) with contextlib.suppress(Exception): #try: if stream.__class__.__name__ == "TwitchStream": await self.maybe_renew_twitch_bearer_token() embeds = await stream.get_new_clips(log) else: embeds = await stream.get_new_clips(log) log.debug(f"{len(embeds)} clips found in get_new_clips") await self.save_streams() for channel_id in stream.channels: channel = self.bot.get_channel(channel_id) if not channel: continue mention_str, edited_roles = await self._get_mention_str( channel.guild) if mention_str: alert_msg = await self.config.guild( channel.guild).live_message_mention() if alert_msg: content = alert_msg.format(mention=mention_str, stream=stream) else: content = ( "{mention}, {stream} has a new clip!").format( mention=mention_str, stream=escape(str(stream.name), mass_mentions=True, formatting=True), ) else: alert_msg = await self.config.guild( channel.guild).live_message_nomention() if alert_msg: content = alert_msg.format(stream=stream) else: content = ("{stream} has a new clip!").format( stream=escape(str(stream.name), mass_mentions=True, formatting=True)) for embed in embeds: m = await channel.send(content, embed=embed) if edited_roles: for role in edited_roles: await role.edit(mentionable=False) #stream.last_checked = datetime.utcnow().isoformat() # Update the last checked time now that we're at the end. await self.save_streams()
async def fetchwidget(self, ctx, *, server_id: int): """Get data about server by ID via server's widget""" try: widget = await self.bot.fetch_widget(server_id) except discord.Forbidden: await ctx.send(chat.error(_("Widget is disabled for this server."))) return except discord.HTTPException as e: await ctx.send(chat.error(_("Widget for that server is not found: {}").format(e.text))) return try: invite = await widget.fetch_invite() except discord.HTTPException: invite = None em = discord.Embed( title=_("Server info"), color=await ctx.embed_color(), url=widget.json_url ) em.add_field(name=_("Name"), value=chat.escape(widget.name, formatting=True)) stats_text = _( "**Online member count:** {members}\n" "**Voice channel count:** {channels}" ).format(members=len(widget.members), channels=len(widget.channels)) if invite: guild = invite.guild em.description = guild.description and guild.description or None stats_text += "\n" + _( "**Server ID**: {guild_id}\n" "**Approximate member count:** {approx_members}\n" "**Approx. active members count:** {approx_active}\n" "**Invite Channel:** {channel}" ).format( guild_id=guild.id, approx_members=invite.approximate_member_count, approx_active=invite.approximate_presence_count, channel=chat.escape(invite.channel.name, formatting=True), ) if guild.features: em.add_field( name=_("Features"), value="\n".join(_(GUILD_FEATURES.get(f, f)) for f in guild.features).format( banner=guild.banner and f" [🔗]({guild.banner_url_as(format='png')})" or "", splash=guild.splash and f" [🔗]({guild.splash_url_as(format='png')})" or "", discovery=getattr(guild, "discovery_splash", None) and f" [🔗]({guild.discovery_splash_url_as(format='png')})" or "", ), inline=False, ) if invite.guild.icon: em.set_image(url=invite.guild.icon_url_as(static_format="png", size=4096)) em.add_field(name=_("Stats"), value=stats_text, inline=False) if widget.invite_url: em.add_field(name=_("Widget's invite"), value=widget.invite_url) await ctx.send(embed=em)
async def __flipx(self, ctx, *, text=None): """Flips a coin... or text/mention. Defaults to coin. """ if text != None and len(text) > 0: if len(ctx.message.mentions) > 0: member = ctx.message.mentions[0] elif len(ctx.message.channel_mentions) > 0: channel = ctx.message.channel_mentions[0] text = "#" + channel.name member = None elif len(ctx.message.role_mentions) > 0: role = ctx.message.role_mentions[0] text = role.name member = None else: member = discord.utils.find( lambda m: m.name.lower() == text.lower(), ctx.bot.get_all_members()) msg = "" if member != None: if member.id == self.bot.user.id: member = ctx.message.author msg = "Nice try. You think this is funny? How about *this* instead:\n\n" text = member.display_name new_text = text.translate(self._flipmap)[::-1] await ctx.send("{} (╯°□°)╯︵ {}".format( msg, escape(new_text, mass_mentions=True))) else: author = ctx.message.author await ctx.send("I Choose: ***{}***".format( choice(["HEADS", "TAILS"])))
async def format_page(self, menu: menus.MenuPages, entries: List[Tuple[int, Dict]]): ctx = menu.ctx loses_len = max(len(humanize_number(entries[0][1]["loses"])) + 3, 8) win_len = max(len(humanize_number(entries[0][1]["wins"])) + 3, 6) xp__len = max(len(humanize_number(entries[0][1]["xp__earnings"])) + 3, 8) gold__len = max(len(humanize_number(entries[0][1]["gold__losses"])) + 3, 12) start_position = (menu.current_page * self.per_page) + 1 pos_len = len(str(start_position + 9)) + 2 header = ( f"{'#':{pos_len}}{'Wins':{win_len}}" f"{'Losses':{loses_len}}{'XP Won':{xp__len}}{'Gold Spent':{gold__len}}{'Adventurer':2}" ) author = ctx.author if getattr(ctx, "guild", None): guild = ctx.guild else: guild = None players = [] for (position, (user_id, account_data)) in enumerate(entries, start=start_position): if guild is not None: member = guild.get_member(user_id) else: member = None if member is not None: username = member.display_name else: user = await menu.ctx.bot.get_user_global(user_id) if user is None: username = user_id else: username = user.name username = escape(str(username), formatting=True) if user_id == author.id: # Highlight the author's position username = f"<<{username}>>" pos_str = position loses = humanize_number(account_data["loses"]) wins = humanize_number(account_data["wins"]) xp__earnings = humanize_number(account_data["xp__earnings"]) gold__losses = humanize_number(account_data["gold__losses"]) data = ( f"{f'{pos_str}.':{pos_len}} " f"{wins:{win_len}} " f"{loses:{loses_len}} " f"{xp__earnings:{xp__len}} " f"{gold__losses:{gold__len}} " f"{username}" ) players.append(data) msg = "Adventure Negaverse Scoreboard\n```md\n{}``` ```md\n{}``````md\n{}```".format( header, "\n".join(players), f"Page {menu.current_page + 1}/{self.get_max_pages()}" ) return msg
async def cmd_report(self, ctx: commands.Context, *, message: str = None): """Sends a report to the mods for possible intervention Example: - `[p]report <message>` """ # Pre-emptively delete the message for privacy reasons await ctx.message.delete() author = ctx.author if author.bot: # Ignore the bot return log_id = await self.settings.guild(ctx.guild).logchannel() log = None if log_id is not None: log = ctx.guild.get_channel(log_id) if log is None: # Failed to get the channel return data = discord.Embed(color=discord.Color.orange()) data.set_author(name=f"Report", icon_url=author.avatar_url) data.add_field(name="Reporter", value=author.mention) data.add_field(name="Channel", value=ctx.channel.mention) data.add_field(name="Timestamp", value=ctx.message.created_at) data.add_field(name="Message", value=escape(message or "<no message>"), inline=False) await log.send(embed=data)
async def format_page(self, menu: GenericMenu, entries): bot = menu.ctx.bot position = (menu.current_page * self.per_page) + 1 bal_len = len(humanize_number(entries[0][1])) pound_len = len(str(position + 9)) header = "{pound:{pound_len}}{score:{bal_len}}{name:2}\n".format( pound="#", name=("Name"), score=("Score"), bal_len=bal_len + 6, pound_len=pound_len + 3, ) msg = "" for i, data in enumerate(entries, start=position): try: server = bot.get_guild(int(data[0])).name except AttributeError: server = "<unknown server>" name = escape(server, formatting=True) balance = data[1] balance = humanize_number(balance) msg += f"{humanize_number(i)}. {balance: <{bal_len + 5}} {name}\n" bank_name = "Guild Command Leaderboard." page = discord.Embed( title=("{}").format(bank_name), color=await menu.ctx.embed_color(), description="{}\n{} ".format(box(header, lang="prolog"), box(msg, lang="md")), ) page.set_footer(text=f"Page {menu.current_page + 1}/{self.get_max_pages()}") return page
async def rndactivity_list(self, ctx: commands.Context): statuses = list(await self.config.statuses()) if not statuses: return await ctx.send( warning(translate("no_setup_statuses", prefix=ctx.prefix))) pages = [] for status in statuses: index = statuses.index(status) + 1 game_type = 0 stream_url = None if isinstance(status, dict): game_type = status.get("type", 0) stream_url = status.get("url") status = status.get("game") status = escape(status, formatting=True, mass_mentions=True) if stream_url: status = f"[{status}]({stream_url})" pages.append( f"**#{index}** \N{EM DASH} **{translate('game_type')[game_type]}** {status}" ) colour = await ctx.embed_colour() pages = [ discord.Embed(colour=colour, description=x) for x in pagify("\n".join(pages)) ] await PaginatedMenu(pages=pages, bot=ctx.bot, channel=ctx.channel, member=ctx.author).prompt()
async def quote_create(self, ctx, *items): """ If a minimum required role has been set, users must have that role or higher, be in the mod/admin role, or be the guild owner in order to use this command The quote will only be created if all information is provided properly. Porper format is Double quotes surrounding quote followed by double quotes surrounding where its from/who its by """ items = [escape(c, mass_mentions=True) for c in items] if len(items) == 2: channel = ctx.guild.get_channel(await self.settings.guild(ctx.guild ).channel()) if channel is None: channel = guild.system_channel # noqa: F821 quote = items[0] author = items[1] content = quote + " # " + author quoteimage = self.quoteImg(content) imfile = discord.File(fp=quoteimage, filename="image.png") embed = discord.Embed(description=quote + " - " + author) embed.set_image(url="attachment://" + quoteimage) await channel.send(embed=embed, file=imfile) await ctx.send("Posted") else: await ctx.send( "Not properly formatted. Porper format is double quotes surrounding quote followed by double quotes surrounding where its from/who its by" )
async def convert( self, ctx: commands.Context, argument: str) -> Tuple[Optional[discord.TextChannel], int]: if argument.isnumeric(): return (None, int(argument)) arg = argument.split("-") if len(arg) != 2 or not all(x.isnumeric() for x in arg): raise commands.BadArgument( translate("invalid_id", mid=escape(argument, mass_mentions=True, formatting=True))) cid, mid = tuple(int(x) for x in arg) channel: discord.TextChannel = ctx.bot.get_channel(cid) # ensure the channel exists and is in a guild context guild: Optional[discord.Guild] = getattr(channel, "guild", None) if not channel or not guild or ctx.author not in guild.members: raise commands.BadArgument(translate("no_such_channel", id=cid)) if not channel.permissions_for(guild.get_member( ctx.author.id)).read_message_history: # we're returning the generic no such channel string if the command invoker is not in # the guild the specified channel is in, so at this point it's safe to say if you're # determined enough, you could probably figure out that a channel exists with a given # ID given that the Discord API makes no real attempts to hide them, which makes # returning a generic not found message pointless. raise commands.BadArgument(translate("no_history_perms", id=cid)) return (channel, mid)
async def listguilds(self, ctx): """List the guilds|servers the bot is in.""" asciidoc = lambda m: "```asciidoc\n{}\n```".format(m) guilds = sorted(self.bot.guilds, key=lambda g: -g.member_count) header = ("```\n" "The bot is in the following {} server{}:\n" "```").format( len(guilds), "s" if len(guilds) > 1 else "" ) max_zpadding = max([len(str(g.member_count)) for g in guilds]) form = "{gid} :: {mems:0{zpadding}} :: {name}" all_forms = [ form.format( gid=g.id, mems=g.member_count, name=filter_invites(cf.escape(g.name)), zpadding=max_zpadding ) for g in guilds ] final = "\n".join(all_forms) await ctx.send(header) page_list = [] for page in cf.pagify(final, delims=["\n"], page_length=1000): page_list.append(asciidoc(page)) if len(page_list) == 1: return await ctx.send(asciidoc(page)) await menu(ctx, page_list, DEFAULT_CONTROLS)
async def convert(self, ctx, argument: str) -> timedelta: # this doc string is intentionally left empty; use `from_str` instead # of directly calling this method. """""" try: return self.from_str(argument) except NoDuration: raise BadArgument( translate( "time.fail_parse_delta", input=escape(argument, mass_mentions=True, formatting=True), ) ) except BelowMinDuration: raise BadArgument( translate( "time.min_duration", delta=format_timedelta(timedelta(seconds=self._min_time)) ) ) except AboveMaxDuration: raise BadArgument( translate( "time.max_duration", delta=format_timedelta(timedelta(seconds=self._max_time)) ) )
async def modlog_action( self, message: discord.Message, trigger: Trigger, find: List[str], action: str ) -> None: modlogs = await self.config.guild(message.guild).modlog() guild: discord.Guild = cast(discord.Guild, message.guild) author: discord.Member = cast(discord.Member, message.author) channel: discord.TextChannel = cast(discord.TextChannel, message.channel) if modlogs: if modlogs == "default": # We'll get the default modlog channel setup # with modlogset try: modlog_channel = await modlog.get_modlog_channel(guild) except RuntimeError: log.debug("Error getting modlog channel", exc_info=True) # Return early if no modlog channel exists return else: modlog_channel = guild.get_channel(modlogs) if modlog_channel is None: return infomessage = f"{author} - {action}\n" embed = discord.Embed( description=message.content, colour=discord.Colour.dark_red(), timestamp=datetime.now(), ) found_regex = humanize_list(find) embed.add_field(name=_("Channel"), value=channel.mention) embed.add_field(name=_("Trigger Name"), value=trigger.name) if found_regex: embed.add_field(name=_("Found Triggers"), value=found_regex[:1024]) embed.add_field(name=_("Trigger author"), value=f"<@{trigger.author}>") if message.attachments: files = ", ".join(a.filename for a in message.attachments) embed.add_field(name=_("Attachments"), value=files) embed.set_footer(text=_("User ID: ") + str(message.author.id)) embed.set_author(name=infomessage, icon_url=author.avatar_url) try: if modlog_channel.permissions_for(guild.me).embed_links: await modlog_channel.send(embed=embed) else: infomessage += _( "Channel: {channel}\n" "Trigger Name: {trigger}\n" "Trigger author: {t_author}\n" "Found Triggers: {found_triggers}\n" ).format( channel=channel.mention, trigger=trigger.name, t_author=f"{trigger.author}", found_triggers=humanize_list(find)[:1024], ) msg = escape( infomessage.replace("@&", ""), mass_mentions=True, formatting=True ) await modlog_channel.send(msg) except Exception: log.error("Error posting modlog message", exc_info=True) pass
async def rinfo(self, ctx, *, role: discord.Role): """Get info about role""" em = discord.Embed( title=chat.escape(role.name, formatting=True), color=role.color if role.color.value else discord.Embed.Empty, ) em.add_field(name=_("ID"), value=role.id) em.add_field( name=_("Permissions"), value="[{0}](https://fixator10.ru/permissions-calculator/?v={0})". format(role.permissions.value), ) em.add_field( name=_("Exists since"), value=role.created_at.strftime(self.TIME_FORMAT), ) em.add_field(name=_("Hoist"), value=bool_emojify(role.hoist)) em.add_field(name=_("Members"), value=str(len(role.members))) em.add_field(name=_("Position"), value=role.position) em.add_field(name=_("Color"), value=role.colour) em.add_field(name=_("Managed"), value=bool_emojify(role.managed)) em.add_field(name=_("Mentionable"), value=bool_emojify(role.mentionable)) em.add_field(name=_("Mention"), value=role.mention + "\n`" + role.mention + "`") em.set_thumbnail( url= f"https://xenforo.com/community/rgba.php?r={role.colour.r}&g={role.color.g}&b={role.color.b}&a=255" ) await ctx.send(embed=em)
async def get_track_description(self, track, local_folder_current_path, shorten=False) -> Optional[str]: """Get the user facing formatted track name.""" string = None if track and getattr(track, "uri", None): query = Query.process_input(track.uri, local_folder_current_path) if query.is_local or "localtracks/" in track.uri: if (hasattr(track, "title") and track.title != "Unknown title" and hasattr(track, "author") and track.author != "Unknown artist"): if shorten: string = f"{track.author} - {track.title}" if len(string) > 40: string = f"{(string[:40]).rstrip(' ')}..." string = f'**{escape(f"{string}", formatting=True)}**' else: string = ( f'**{escape(f"{track.author} - {track.title}", formatting=True)}**' + escape(f"\n{query.to_string_user()} ", formatting=True)) elif hasattr(track, "title") and track.title != "Unknown title": if shorten: string = f"{track.title}" if len(string) > 40: string = f"{(string[:40]).rstrip(' ')}..." string = f'**{escape(f"{string}", formatting=True)}**' else: string = f'**{escape(f"{track.title}", formatting=True)}**' + escape( f"\n{query.to_string_user()} ", formatting=True) else: string = query.to_string_user() if shorten and len(string) > 40: string = f"{(string[:40]).rstrip(' ')}..." string = f'**{escape(f"{string}", formatting=True)}**' else: if track.is_stream: icy = await self.icyparser(track.uri) if icy: title = icy else: title = f"{track.title} - {track.author}" elif track.author.lower() not in track.title.lower(): title = f"{track.title} - {track.author}" else: title = track.title string = f"{title}" if shorten and len(string) > 40: string = f"{(string[:40]).rstrip(' ')}..." string = re.sub(RE_SQUARE, "", string) string = f"**[{escape(string, formatting=True)}]({track.uri}) **" elif hasattr(track, "to_string_user") and track.is_local: string = track.to_string_user() + " " if shorten and len(string) > 40: string = f"{(string[:40]).rstrip(' ')}..." string = f'**{escape(f"{string}", formatting=True)}**' return string
async def build_tweet_embed(self, status: tweepy.Status) -> discord.Embed: username = status.user.screen_name post_url = "https://twitter.com/{}/status/{}".format(status.user.screen_name, status.id) em = discord.Embed( colour=discord.Colour(value=int(status.user.profile_link_color, 16)), url=post_url, timestamp=status.created_at, ) em.set_footer(text=f"@{username}") if hasattr(status, "retweeted_status"): em.set_author( name=f"{status.user.name} Retweeted {status.retweeted_status.user.name}", url=post_url, icon_url=status.user.profile_image_url, ) status = status.retweeted_status em.set_footer(text=f"@{username} RT @{status.user.screen_name}") if hasattr(status, "extended_entities"): em.set_image(url=status.extended_entities["media"][0]["media_url_https"]) if hasattr(status, "extended_tweet"): text = status.extended_tweet["full_text"] if "media" in status.extended_tweet["entities"]: img = status.extended_tweet["entities"]["media"][0]["media_url_https"] em.set_image(url=img) else: text = status.text else: em.set_author( name=status.user.name, url=post_url, icon_url=status.user.profile_image_url ) if hasattr(status, "extended_entities"): em.set_image(url=status.extended_entities["media"][0]["media_url_https"]) if hasattr(status, "extended_tweet"): text = status.extended_tweet["full_text"] if "media" in status.extended_tweet["entities"]: img = status.extended_tweet["entities"]["media"][0]["media_url_https"] em.set_image(url=img) else: text = status.text if status.in_reply_to_screen_name: api = await self.authenticate() try: reply = api.statuses_lookup(id_=[status.in_reply_to_status_id])[0] # log.debug(reply) in_reply_to = _("In reply to {name} (@{screen_name})").format( name=reply.user.name, screen_name=reply.user.screen_name ) reply_text = unescape(reply.text) if hasattr(reply, "extended_tweet"): reply_text = unescape(reply.extended_tweet["full_text"]) if hasattr(reply, "extended_entities") and not em.image: em.set_image(url=reply.extended_entities["media"][0]["media_url_https"]) em.add_field(name=in_reply_to, value=reply_text) except IndexError: log.debug("Error grabbing in reply to tweet.", exc_info=True) em.description = escape(unescape(text), formatting=True) return em
async def format_page(self, menu: menus.MenuPages, entries: List[Tuple[int, Dict]]): ctx = menu.ctx stats_len = len(humanize_number(entries[0][1][self._stat])) + 3 start_position = (menu.current_page * self.per_page) + 1 pos_len = len(str(start_position + 9)) + 2 stats_plural = self._stat if self._stat.endswith( "s") else f"{self._stat}s" stats_len = (len(stats_plural) if len(stats_plural) > stats_len else stats_len) + 2 rebirth_len = len("Rebirths") + 2 header = f"{'#':{pos_len}}{stats_plural.title().ljust(stats_len)}{'Rebirths':{rebirth_len}}{'Adventurer':2}" author = ctx.author if getattr(ctx, "guild", None): guild = ctx.guild else: guild = None players = [] for (position, (user_id, account_data)) in enumerate(entries, start=start_position): if guild is not None: member = guild.get_member(user_id) else: member = None if member is not None: username = member.display_name else: user = menu.ctx.bot.get_user(user_id) if user is None: username = user_id else: username = user.name username = escape(str(username), formatting=True) if user_id == author.id: # Highlight the author's position username = f"<<{username}>>" pos_str = position rebirths = humanize_number(account_data["rebirths"]) stats_value = humanize_number(account_data[self._stat.lower()]) data = f"{f'{pos_str}.':{pos_len}}" f"{stats_value:{stats_len}}" f"{rebirths:{rebirth_len}}" f"{username}" players.append(data) embed = discord.Embed( title=f"Adventure Weekly Scoreboard", color=await menu.ctx.embed_color(), description="```md\n{}``` ```md\n{}```".format( header, "\n".join(players), ), ) embed.set_footer( text=f"Page {menu.current_page + 1}/{self.get_max_pages()}") return embed
def __init__( self, service: str, http_status: int, result: bool, reason: str = "", ): """Create the base Report result.""" self.service = service self.http_status = http_status self.result = result self.reason = escape(reason, mass_mentions=True)
async def choose(self, ctx, *choices): """Choose between multiple options. To denote options which include whitespace, you should use double quotes. """ choices = [escape(c, mass_mentions=True) for c in choices] if len(choices) < 2: await ctx.send(_("Not enough options to pick from.")) else: await ctx.send(choice(choices))
async def cc_list(self, ctx: commands.Context): """List all available custom commands. The list displays a preview of each command's response, with markdown escaped and newlines replaced with spaces. """ cc_dict = await CommandObj.get_commands(self.config.guild(ctx.guild)) if not cc_dict: await ctx.send( _( "There are no custom commands in this server." " Use `{command}` to start adding some." ).format(command="{}customcom create".format(ctx.prefix)) ) return results = [] for command, body in sorted(cc_dict.items(), key=lambda t: t[0]): responses = body["response"] if isinstance(responses, list): result = ", ".join(responses) elif isinstance(responses, str): result = responses else: continue # Cut preview to 52 characters max if len(result) > 52: result = result[:49] + "..." # Replace newlines with spaces result = result.replace("\n", " ") # Escape markdown and mass mentions result = escape(result, formatting=True, mass_mentions=True) results.append((f"{ctx.clean_prefix}{command}", result)) if await ctx.embed_requested(): # We need a space before the newline incase the CC preview ends in link (GH-2295) content = " \n".join(map("**{0[0]}** {0[1]}".format, results)) pages = list(pagify(content, page_length=1024)) embed_pages = [] for idx, page in enumerate(pages, start=1): embed = discord.Embed( title=_("Custom Command List"), description=page, colour=await ctx.embed_colour(), ) embed.set_footer(text=_("Page {num}/{total}").format(num=idx, total=len(pages))) embed_pages.append(embed) await menus.menu(ctx, embed_pages, menus.DEFAULT_CONTROLS) else: content = "\n".join(map("{0[0]:<12} : {0[1]}".format, results)) pages = list(map(box, pagify(content, page_length=2000, shorten_by=10))) await menus.menu(ctx, pages, menus.DEFAULT_CONTROLS)
async def lmgtfy(self, ctx, *, search_terms: str): """Create a lmgtfy link.""" search_terms = escape( search_terms.replace("+", "%2B").replace(" ", "+"), mass_mentions=True ) await ctx.send("https://lmgtfy.com/?q={}".format(search_terms))