async def _build_queue_search_page( self, ctx: commands.Context, page_num: int, search_list: List[Tuple[int, str]]) -> discord.Embed: search_num_pages = math.ceil(len(search_list) / 10) search_idx_start = (page_num - 1) * 10 search_idx_end = search_idx_start + 10 track_match = "" async for i, track in AsyncIter( search_list[search_idx_start:search_idx_end]).enumerate( start=search_idx_start): track_idx = i + 1 if type(track) is str: track_location = LocalPath( track, self.local_folder_current_path).to_string_user() track_match += "`{}.` **{}**\n".format(track_idx, track_location) else: track_match += "`{}.` **{}**\n".format(track[0], track[1]) embed = discord.Embed(colour=await ctx.embed_colour(), title=_("Matching Tracks:"), description=track_match) embed.set_footer(text=_( "Page {page_num}/{total_pages} | {num_tracks} tracks").format( page_num=humanize_number(page_num), total_pages=humanize_number(search_num_pages), num_tracks=len(search_list), )) return embed
async def slotmax(self, ctx: commands.Context, bid: positive_int): """Set the maximum slot machine bid. Example: - `[p]economyset slotmax 50` **Arguments** - `<bid>` The new maximum bid for using the slot machine. Default is 100. """ guild = ctx.guild is_global = await bank.is_global() if is_global: slot_min = await self.config.SLOT_MIN() else: slot_min = await self.config.guild(guild).SLOT_MIN() if bid < slot_min: await ctx.send( _("Warning: Maximum bid is less than the minimum bid ({min_bid}). " "Slots will not work.").format( min_bid=humanize_number(slot_min))) credits_name = await bank.get_currency_name(guild) if is_global: await self.config.SLOT_MAX.set(bid) else: await self.config.guild(guild).SLOT_MAX.set(bid) await ctx.send( _("Maximum bid is now {bid} {currency}.").format( bid=humanize_number(bid), currency=credits_name))
def make_embed(self, data): is_rerun = data["type"] == "rerun" url = f"https://www.twitch.tv/{data['login']}" if data[ "login"] is not None else None logo = data["profile_image_url"] if logo is None: logo = "https://static-cdn.jtvnw.net/jtv_user_pictures/xarth/404_user_70x70.png" status = data["title"] if not status: status = _("Untitled broadcast") if is_rerun: status += _(" - Rerun") embed = discord.Embed(title=status, url=url, color=0x6441A4) embed.set_author(name=data["user_name"]) embed.add_field(name=_("Followers"), value=humanize_number(data["followers"])) embed.add_field(name=_("Total views"), value=humanize_number(data["view_count"])) embed.set_thumbnail(url=logo) if data["thumbnail_url"]: embed.set_image( url=rnd(data["thumbnail_url"].format(width=320, height=180))) if data["game_name"]: embed.set_footer(text=_("Playing: ") + data["game_name"]) return embed
async def bankset_showsettings(self, ctx: commands.Context): """Show the current bank settings.""" cur_setting = await bank.is_global() if cur_setting: group = bank._config else: if not ctx.guild: return group = bank._config.guild(ctx.guild) group_data = await group.all() bank_name = group_data["bank_name"] bank_scope = _("Global") if cur_setting else _("Server") currency_name = group_data["currency"] default_balance = group_data["default_balance"] max_balance = group_data["max_balance"] settings = _( "Bank settings:\n\nBank name: {bank_name}\nBank scope: {bank_scope}\n" "Currency: {currency_name}\nDefault balance: {default_balance}\n" "Maximum allowed balance: {maximum_bal}\n").format( bank_name=bank_name, bank_scope=bank_scope, currency_name=currency_name, default_balance=humanize_number(default_balance), maximum_bal=humanize_number(max_balance), ) await ctx.send(box(settings))
def make_embed(self, data): avatar = rnd( "https://picarto.tv/user_data/usrimg/{}/dsdefault.jpg".format( data["name"].lower())) url = "https://picarto.tv/" + data["name"] thumbnail = data["thumbnails"]["web"] embed = discord.Embed(title=data["title"], url=url, color=0x4C90F3) embed.set_author(name=data["name"]) embed.set_image(url=rnd(thumbnail)) embed.add_field(name=_("Followers"), value=humanize_number(data["followers"])) embed.add_field(name=_("Total views"), value=humanize_number(data["viewers_total"])) embed.set_thumbnail(url=avatar) data["tags"] = ", ".join(data["tags"]) if not data["tags"]: data["tags"] = _("None") if data["adult"]: data["adult"] = _("NSFW | ") else: data["adult"] = "" embed.set_footer( text=_("{adult}Category: {category} | Tags: {tags}").format( **data)) return embed
async def _set(self, ctx: commands.Context, to: discord.Member, creds: SetParser): """Set the balance of a user's bank account. Putting + or - signs before the amount will add/remove currency on the user's bank account instead. Examples: - `[p]bank set @Twentysix 26` - Sets balance to 26 - `[p]bank set @Twentysix +2` - Increases balance by 2 - `[p]bank set @Twentysix -6` - Decreases balance by 6 **Arguments** - `<to>` The user to set the currency of. - `<creds>` The amount of currency to set their balance to. """ author = ctx.author currency = await bank.get_currency_name(ctx.guild) try: if creds.operation == "deposit": await bank.deposit_credits(to, creds.sum) msg = _("{author} added {num} {currency} to {user}'s account." ).format( author=author.display_name, num=humanize_number(creds.sum), currency=currency, user=to.display_name, ) elif creds.operation == "withdraw": await bank.withdraw_credits(to, creds.sum) msg = _( "{author} removed {num} {currency} from {user}'s account." ).format( author=author.display_name, num=humanize_number(creds.sum), currency=currency, user=to.display_name, ) else: await bank.set_balance(to, creds.sum) msg = _( "{author} set {user}'s account balance to {num} {currency}." ).format( author=author.display_name, num=humanize_number(creds.sum), currency=currency, user=to.display_name, ) except (ValueError, errors.BalanceTooHigh) as e: await ctx.send(str(e)) else: await ctx.send(msg)
async def bankset_maxbal(self, ctx: commands.Context, *, amount: int): """Set the maximum balance a user can get.""" try: await bank.set_max_balance(amount, ctx.guild) except ValueError: # noinspection PyProtectedMember return await ctx.send( _("Amount must be greater than zero and less than {max}."). format(max=humanize_number(bank._MAX_BALANCE))) await ctx.send( _("Maximum balance has been set to: {amount}").format( amount=humanize_number(amount)))
async def balance(self, ctx: commands.Context, user: discord.Member = None): """Show the user's account balance. Example: - `[p]bank balance` - `[p]bank balance @Twentysix` **Arguments** - `<user>` The user to check the balance of. If omitted, defaults to your own balance. """ if user is None: user = ctx.author bal = await bank.get_balance(user) currency = await bank.get_currency_name(ctx.guild) max_bal = await bank.get_max_balance(ctx.guild) if bal > max_bal: bal = max_bal await bank.set_balance(user, bal) await ctx.send( _("{user}'s balance is {num} {currency}").format( user=user.display_name, num=humanize_number(bal), currency=currency))
async def deposit_credits(member: discord.Member, amount: int) -> int: """Add a given amount of credits to an account. Parameters ---------- member : discord.Member The member to deposit credits to. amount : int The amount to deposit. Returns ------- int The new balance. Raises ------ ValueError If the deposit amount is invalid. TypeError If the deposit amount is not an `int`. """ if not isinstance(amount, int): raise TypeError("Deposit amount must be of type int, not {}.".format( type(amount))) if _invalid_amount(amount): raise ValueError("Invalid deposit amount {} <= 0".format( humanize_number(amount, override_locale="en_US"))) bal = await get_balance(member) return await set_balance(member, amount + bal)
async def wrapped(*args, **kwargs): context: commands.Context = None for arg in args: if isinstance(arg, commands.Context): context = arg break if not context.guild and not await is_global(): raise commands.UserFeedbackCheckFailure( _("Can't pay for this command in DM without a global bank." )) try: await withdraw_credits(context.author, amount) except Exception: credits_name = await get_currency_name(context.guild) raise commands.UserFeedbackCheckFailure( _("You need at least {cost} {currency} to use this command." ).format(cost=humanize_number(amount), currency=credits_name)) else: try: return await coro(*args, **kwargs) except AbortPurchase: await deposit_credits(context.author, amount) except Exception: await deposit_credits(context.author, amount) raise
async def transfer(self, ctx: commands.Context, to: discord.Member, amount: int): """Transfer currency to other users. This will come out of your balance, so make sure you have enough. Example: - `[p]bank transfer @Twentysix 500` **Arguments** - `<to>` The user to give currency to. - `<amount>` The amount of currency to give. """ from_ = ctx.author currency = await bank.get_currency_name(ctx.guild) try: await bank.transfer_credits(from_, to, amount) except (ValueError, errors.BalanceTooHigh) as e: return await ctx.send(str(e)) await ctx.send( _("{user} transferred {num} {currency} to {other_user}").format( user=from_.display_name, num=humanize_number(amount), currency=currency, other_user=to.display_name, ))
async def economyset_showsettings(self, ctx: commands.Context): """ Shows the current economy settings """ guild = ctx.guild if await bank.is_global(): conf = self.config else: conf = self.config.guild(guild) await ctx.send( box( _("----Economy Settings---\n" "Minimum slot bid: {slot_min}\n" "Maximum slot bid: {slot_max}\n" "Slot cooldown: {slot_time}\n" "Payday amount: {payday_amount}\n" "Payday cooldown: {payday_time}\n" "Amount given at account registration: {register_amount}\n" "Maximum allowed balance: {maximum_bal}").format( slot_min=humanize_number(await conf.SLOT_MIN()), slot_max=humanize_number(await conf.SLOT_MAX()), slot_time=humanize_number(await conf.SLOT_TIME()), payday_time=humanize_number(await conf.PAYDAY_TIME()), payday_amount=humanize_number(await conf.PAYDAY_CREDITS()), register_amount=humanize_number( await bank.get_default_balance(guild)), maximum_bal=humanize_number(await bank.get_max_balance(guild)), )))
async def rolepaydayamount(self, ctx: commands.Context, role: discord.Role, creds: int): """Set the amount earned each payday for a role. Set to `0` to remove the payday amount you set for that role. Only available when not using a global bank. Example: - `[p]economyset rolepaydayamount @Members 400` **Arguments** - `<role>` The role to assign a custom payday amount to. - `<creds>` The new amount to give when using the payday command. """ guild = ctx.guild max_balance = await bank.get_max_balance(ctx.guild) if creds >= max_balance: return await ctx.send( _("The bank requires that you set the payday to be less than" " its maximum balance of {maxbal}.").format( maxbal=humanize_number(max_balance))) credits_name = await bank.get_currency_name(guild) if await bank.is_global(): await ctx.send( _("The bank must be per-server for per-role paydays to work.")) else: if creds <= 0: # Because I may as well... default_creds = await self.config.guild(guild).PAYDAY_CREDITS() await self.config.role(role).clear() await ctx.send( _("The payday value attached to role has been removed. " "Users with this role will now receive the default pay " "of {num} {currency}.").format( num=humanize_number(default_creds), currency=credits_name)) else: await self.config.role(role).PAYDAY_CREDITS.set(creds) await ctx.send( _("Every payday will now give {num} {currency} " "to people with the role {role_name}.").format( num=humanize_number(creds), currency=credits_name, role_name=role.name))
async def command_audiostats(self, ctx: commands.Context): """Audio stats.""" server_num = len(lavalink.active_players()) total_num = len(lavalink.all_players()) msg = "" async for p in AsyncIter(lavalink.all_players()): connect_start = p.fetch("connect") connect_dur = self.get_time_string( int((datetime.datetime.utcnow() - connect_start).total_seconds())) try: if not p.current: raise AttributeError current_title = await self.get_track_description( p.current, self.local_folder_current_path) msg += "{} [`{}`]: {}\n".format(p.channel.guild.name, connect_dur, current_title) except AttributeError: msg += "{} [`{}`]: **{}**\n".format(p.channel.guild.name, connect_dur, _("Nothing playing.")) if total_num == 0: return await self.send_embed_msg( ctx, title=_("Not connected anywhere.")) servers_embed = [] pages = 1 for page in pagify(msg, delims=["\n"], page_length=1500): em = discord.Embed( colour=await ctx.embed_colour(), title=_("Playing in {num}/{total} servers:").format( num=humanize_number(server_num), total=humanize_number(total_num)), description=page, ) em.set_footer(text=_("Page {}/{}").format( humanize_number(pages), humanize_number((math.ceil(len(msg) / 1500))))) pages += 1 servers_embed.append(em) await menu(ctx, servers_embed, DEFAULT_CONTROLS)
async def roll(self, ctx, number: int = 100): """Roll a random number. The result will be between 1 and `<number>`. `<number>` defaults to 100. """ author = ctx.author if 1 < number <= MAX_ROLL: n = randint(1, number) await ctx.send("{author.mention} :game_die: {n} :game_die:".format( author=author, n=humanize_number(n))) elif number <= 1: await ctx.send( _("{author.mention} Maybe higher than 1? ;P").format( author=author)) else: await ctx.send( _("{author.mention} Max allowed number is {maxamount}."). format(author=author, maxamount=humanize_number(MAX_ROLL)))
async def withdraw_credits(member: discord.Member, amount: int) -> int: """Remove a certain amount of credits from an account. Parameters ---------- member : discord.Member The member to withdraw credits from. amount : int The amount to withdraw. Returns ------- int New account balance. Raises ------ ValueError If the withdrawal amount is invalid or if the account has insufficient funds. TypeError If the withdrawal amount is not an `int`. """ if not isinstance(amount, int): raise TypeError( "Withdrawal amount must be of type int, not {}.".format( type(amount))) if _invalid_amount(amount): raise ValueError("Invalid withdrawal amount {} < 0".format( humanize_number(amount, override_locale="en_US"))) bal = await get_balance(member) if amount > bal: raise ValueError("Insufficient funds {} > {}".format( humanize_number(amount, override_locale="en_US"), humanize_number(bal, override_locale="en_US"), )) return await set_balance(member, bal - amount)
async def registeramount(self, ctx: commands.Context, creds: int): """Set the initial balance for new bank accounts. Example: - `[p]economyset registeramount 5000` **Arguments** - `<creds>` The new initial balance amount. Default is 0. """ guild = ctx.guild max_balance = await bank.get_max_balance(ctx.guild) credits_name = await bank.get_currency_name(guild) try: await bank.set_default_balance(creds, guild) except ValueError: return await ctx.send( _("Amount must be greater than or equal to zero and less than {maxbal}." ).format(maxbal=humanize_number(max_balance))) await ctx.send( _("Registering an account will now give {num} {currency}.").format( num=humanize_number(creds), currency=credits_name))
async def transfer_credits( from_: Union[discord.Member, discord.User], to: Union[discord.Member, discord.User], amount: int, ): """Transfer a given amount of credits from one account to another. Parameters ---------- from_: Union[discord.Member, discord.User] The member to transfer from. to : Union[discord.Member, discord.User] The member to transfer to. amount : int The amount to transfer. Returns ------- int The new balance of the member gaining credits. Raises ------ ValueError If the amount is invalid or if ``from_`` has insufficient funds. TypeError If the amount is not an `int`. RuntimeError If the bank is guild-specific and a discord.User object is provided. BalanceTooHigh If the balance after the transfer would be greater than ``bank._MAX_BALANCE``. """ if not isinstance(amount, int): raise TypeError("Transfer amount must be of type int, not {}.".format( type(amount))) if _invalid_amount(amount): raise ValueError("Invalid transfer amount {} <= 0".format( humanize_number(amount, override_locale="en_US"))) guild = getattr(to, "guild", None) max_bal = await get_max_balance(guild) if await get_balance(to) + amount > max_bal: currency = await get_currency_name(guild) raise errors.BalanceTooHigh(user=to.display_name, max_balance=max_bal, currency_name=currency) await withdraw_credits(from_, amount) return await deposit_credits(to, amount)
async def maybe_charge_requester(self, ctx: commands.Context, jukebox_price: int) -> bool: jukebox = await self.config.guild(ctx.guild).jukebox() if jukebox and not await self._can_instaskip(ctx, ctx.author): can_spend = await bank.can_spend(ctx.author, jukebox_price) if can_spend: await bank.withdraw_credits(ctx.author, jukebox_price) else: credits_name = await bank.get_currency_name(ctx.guild) bal = await bank.get_balance(ctx.author) await self.send_embed_msg( ctx, title=_("Not enough {currency}").format(currency=credits_name), description=_( "{required_credits} {currency} required, but you have {bal}." ).format( currency=credits_name, required_credits=humanize_number(jukebox_price), bal=humanize_number(bal), ), ) return can_spend else: return True
async def paydayamount(self, ctx: commands.Context, creds: int): """Set the amount earned each payday. Example: - `[p]economyset paydayamount 400` **Arguments** - `<creds>` The new amount to give when using the payday command. Default is 120. """ guild = ctx.guild max_balance = await bank.get_max_balance(ctx.guild) if creds <= 0 or creds > max_balance: return await ctx.send( _("Amount must be greater than zero and less than {maxbal}."). format(maxbal=humanize_number(max_balance))) credits_name = await bank.get_currency_name(guild) if await bank.is_global(): await self.config.PAYDAY_CREDITS.set(creds) else: await self.config.guild(guild).PAYDAY_CREDITS.set(creds) await ctx.send( _("Every payday will now give {num} {currency}.").format( num=humanize_number(creds), currency=credits_name))
async def set_default_balance(amount: int, guild: discord.Guild = None) -> int: """Set the default balance amount. Parameters ---------- amount : int The new default balance. guild : `discord.Guild`, optional The guild to set the default balance for (required if bank is guild-specific). Returns ------- int The new default balance. Raises ------ RuntimeError If the bank is guild-specific and guild was not provided. ValueError If the amount is less than 0 or higher than the max allowed balance. TypeError If the amount is not an `int`. """ if not isinstance(amount, int): raise TypeError("Amount must be of type int, not {}.".format( type(amount))) max_bal = await get_max_balance(guild) if not (0 <= amount <= max_bal): raise ValueError( "Amount must be greater than or equal zero and less than or equal {max}." .format(max=humanize_number(max_bal, override_locale="en_US"))) if await is_global(): await _config.default_balance.set(amount) global _cache _cache["default_balance"] = amount elif guild is not None: await _config.guild(guild).default_balance.set(amount) else: raise RuntimeError("Guild is missing and required.") return amount
def make_embed(self, data): base_url = "https://edge.sf.hitbox.tv" livestream = data["livestream"][0] channel = livestream["channel"] url = channel["channel_link"] embed = discord.Embed(title=livestream["media_status"], url=url, color=0x98CB00) embed.set_author(name=livestream["media_name"]) embed.add_field(name=_("Followers"), value=humanize_number(channel["followers"])) embed.set_thumbnail(url=base_url + channel["user_logo"]) if livestream["media_thumbnail"]: embed.set_image(url=rnd(base_url + livestream["media_thumbnail"])) embed.set_footer(text=_("Playing: ") + livestream["category_name"]) return embed
async def set_max_balance(amount: int, guild: discord.Guild = None) -> int: """Set the maximum balance for the bank. Parameters ---------- amount : int The new maximum balance. guild : `discord.Guild`, optional The guild to set the max balance for (required if bank is guild-specific). Returns ------- int The new maximum balance. Raises ------ RuntimeError If the bank is guild-specific and guild was not provided. ValueError If the amount is less than 0 or higher than 2 ** 63 - 1. TypeError If the amount is not an `int`. """ if not isinstance(amount, int): raise TypeError("Amount must be of type int, not {}.".format( type(amount))) if not (0 < amount <= _MAX_BALANCE): raise ValueError( "Amount must be greater than zero and less than {max}.".format( max=humanize_number(_MAX_BALANCE, override_locale="en_US"))) if await is_global(): await _config.max_balance.set(amount) global _cache _cache["max_balance"] = amount elif guild is not None: await _config.guild(guild).max_balance.set(amount) else: raise RuntimeError( "Guild must be provided if setting the maximum balance of a guild-specific bank." ) return amount
async def command_equalizer_list(self, ctx: commands.Context): """List saved eq presets.""" eq_presets = await self.config.custom("EQUALIZER", ctx.guild.id).eq_presets() if not eq_presets.keys(): return await self.send_embed_msg( ctx, title=_("No saved equalizer presets.")) space = "\N{EN SPACE}" header_name = _("Preset Name") header_author = _("Author") header = box( "[{header_name}]{space}[{header_author}]\n".format( header_name=header_name, space=space * 9, header_author=header_author), lang="ini", ) preset_list = "" for preset, bands in eq_presets.items(): try: author = self.bot.get_user(bands["author"]) except TypeError: author = "None" msg = f"{preset}{space * (22 - len(preset))}{author}\n" preset_list += msg page_list = [] colour = await ctx.embed_colour() for page in pagify(preset_list, delims=[", "], page_length=1000): formatted_page = box(page, lang="ini") embed = discord.Embed(colour=colour, description=f"{header}\n{formatted_page}") embed.set_footer(text=_("{num} preset(s)").format( num=humanize_number(len(list(eq_presets.keys()))))) page_list.append(embed) await menu(ctx, page_list, DEFAULT_CONTROLS)
async def _build_queue_page( self, ctx: commands.Context, queue: list, player: lavalink.player_manager.Player, page_num: int, ) -> discord.Embed: shuffle = await self.config.guild(ctx.guild).shuffle() repeat = await self.config.guild(ctx.guild).repeat() autoplay = await self.config.guild(ctx.guild).auto_play() queue_num_pages = math.ceil(len(queue) / 10) queue_idx_start = (page_num - 1) * 10 queue_idx_end = queue_idx_start + 10 if len(player.queue) > 500: queue_list = _( "__Too many songs in the queue, only showing the first 500__.\n\n" ) else: queue_list = "" arrow = await self.draw_time(ctx) pos = self.format_time(player.position) if player.current.is_stream: dur = "LIVE" else: dur = self.format_time(player.current.length) query = Query.process_input(player.current, self.local_folder_current_path) current_track_description = await self.get_track_description( player.current, self.local_folder_current_path) if query.is_stream: queue_list += _("**Currently livestreaming:**\n") queue_list += f"{current_track_description}\n" queue_list += _("Requested by: **{user}**").format( user=player.current.requester) queue_list += f"\n\n{arrow}`{pos}`/`{dur}`\n\n" else: queue_list += _("Playing: ") queue_list += f"{current_track_description}\n" queue_list += _("Requested by: **{user}**").format( user=player.current.requester) queue_list += f"\n\n{arrow}`{pos}`/`{dur}`\n\n" async for i, track in AsyncIter( queue[queue_idx_start:queue_idx_end]).enumerate( start=queue_idx_start): req_user = track.requester track_idx = i + 1 track_description = await self.get_track_description( track, self.local_folder_current_path, shorten=True) queue_list += f"`{track_idx}.` {track_description}, " queue_list += _("requested by **{user}**\n").format(user=req_user) embed = discord.Embed( colour=await ctx.embed_colour(), title=_("Queue for __{guild_name}__").format( guild_name=ctx.guild.name), description=queue_list, ) if await self.config.guild(ctx.guild ).thumbnail() and player.current.thumbnail: embed.set_thumbnail(url=player.current.thumbnail) queue_dur = await self.queue_duration(ctx) queue_total_duration = self.format_time(queue_dur) text = _( "Page {page_num}/{total_pages} | {num_tracks} tracks, {num_remaining} remaining\n" ).format( page_num=humanize_number(page_num), total_pages=humanize_number(queue_num_pages), num_tracks=len(player.queue), num_remaining=queue_total_duration, ) text += ( _("Auto-Play") + ": " + ("\N{WHITE HEAVY CHECK MARK}" if autoplay else "\N{CROSS MARK}")) text += ( (" | " if text else "") + _("Shuffle") + ": " + ("\N{WHITE HEAVY CHECK MARK}" if shuffle else "\N{CROSS MARK}")) text += ( (" | " if text else "") + _("Repeat") + ": " + ("\N{WHITE HEAVY CHECK MARK}" if repeat else "\N{CROSS MARK}")) embed.set_footer(text=text) return embed
async def command_skip(self, ctx: commands.Context, skip_to_track: int = None): """Skip to the next track, or to a given track number.""" if not self._player_check(ctx): return await self.send_embed_msg(ctx, title=_("Nothing playing.")) player = lavalink.get_player(ctx.guild.id) can_skip = await self._can_instaskip(ctx, ctx.author) if (not ctx.author.voice or ctx.author.voice.channel != player.channel) and not can_skip: return await self.send_embed_msg( ctx, title=_("Unable To Skip Tracks"), description=_( "You must be in the voice channel to skip the music."), ) if not player.current: return await self.send_embed_msg(ctx, title=_("Nothing playing.")) dj_enabled = self._dj_status_cache.setdefault( ctx.guild.id, await self.config.guild(ctx.guild).dj_enabled()) vote_enabled = await self.config.guild(ctx.guild).vote_enabled() is_alone = await self.is_requester_alone(ctx) is_requester = await self.is_requester(ctx, ctx.author) if dj_enabled and not vote_enabled: if not (can_skip or is_requester) and not is_alone: return await self.send_embed_msg( ctx, title=_("Unable To Skip Tracks"), description= _("You need the DJ role or be the track requester to skip tracks." ), ) if (is_requester and not can_skip and isinstance(skip_to_track, int) and skip_to_track > 1): return await self.send_embed_msg( ctx, title=_("Unable To Skip Tracks"), description=_("You can only skip the current track."), ) if vote_enabled: if not can_skip: if skip_to_track is not None: return await self.send_embed_msg( ctx, title=_("Unable To Skip Tracks"), description= _("Can't skip to a specific track in vote mode without the DJ role." ), ) if ctx.author.id in self.skip_votes[ctx.message.guild]: self.skip_votes[ctx.message.guild].remove(ctx.author.id) reply = _("I removed your vote to skip.") else: self.skip_votes[ctx.message.guild].append(ctx.author.id) reply = _("You voted to skip.") num_votes = len(self.skip_votes[ctx.message.guild]) vote_mods = [] for member in player.channel.members: can_skip = await self._can_instaskip(ctx, member) if can_skip: vote_mods.append(member) num_members = len(player.channel.members) - len(vote_mods) vote = int(100 * num_votes / num_members) percent = await self.config.guild(ctx.guild).vote_percent() if vote >= percent: self.skip_votes[ctx.message.guild] = [] await self.send_embed_msg(ctx, title=_("Vote threshold met.")) return await self._skip_action(ctx) else: reply += _( " Votes: {num_votes}/{num_members}" " ({cur_percent}% out of {required_percent}% needed)" ).format( num_votes=humanize_number(num_votes), num_members=humanize_number(num_members), cur_percent=vote, required_percent=percent, ) return await self.send_embed_msg(ctx, title=reply) else: return await self._skip_action(ctx, skip_to_track) else: return await self._skip_action(ctx, skip_to_track)
def __str__(self) -> str: return _( "{user}'s balance cannot rise above {max} {currency}.").format( user=self.user, max=humanize_number(self.max_balance), currency=self.currency_name)
async def leaderboard(self, ctx: commands.Context, top: int = 10, show_global: bool = False): """Print the leaderboard. Defaults to top 10. Examples: - `[p]leaderboard` - `[p]leaderboard 50` - Shows the top 50 instead of top 10. - `[p]leaderboard 100 yes` - Shows the top 100 from all servers. **Arguments** - `<top>` How many positions on the leaderboard to show. Defaults to 10 if omitted. - `<show_global>` Whether to include results from all servers. This will default to false unless specified. """ guild = ctx.guild author = ctx.author embed_requested = await ctx.embed_requested() footer_message = _("Page {page_num}/{page_len}.") max_bal = await bank.get_max_balance(ctx.guild) if top < 1: top = 10 base_embed = discord.Embed(title=_("Economy Leaderboard")) if await bank.is_global() and show_global: # show_global is only applicable if bank is global bank_sorted = await bank.get_leaderboard(positions=top, guild=None) base_embed.set_author(name=ctx.bot.user.name, icon_url=ctx.bot.user.avatar_url) else: bank_sorted = await bank.get_leaderboard(positions=top, guild=guild) if guild: base_embed.set_author(name=guild.name, icon_url=guild.icon_url) try: bal_len = len(humanize_number(bank_sorted[0][1]["balance"])) bal_len_max = len(humanize_number(max_bal)) if bal_len > bal_len_max: bal_len = bal_len_max # first user is the largest we'll see except IndexError: return await ctx.send(_("There are no accounts in the bank.")) pound_len = len(str(len(bank_sorted))) 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, ) highscores = [] pos = 1 temp_msg = header for acc in bank_sorted: try: name = guild.get_member(acc[0]).display_name except AttributeError: user_id = "" if await ctx.bot.is_owner(ctx.author): user_id = f"({str(acc[0])})" name = f"{acc[1]['name']} {user_id}" balance = acc[1]["balance"] if balance > max_bal: balance = max_bal await bank.set_balance(MOCK_MEMBER(acc[0], guild), balance) balance = humanize_number(balance) if acc[0] != author.id: temp_msg += (f"{f'{humanize_number(pos)}.': <{pound_len+2}} " f"{balance: <{bal_len + 5}} {name}\n") else: temp_msg += (f"{f'{humanize_number(pos)}.': <{pound_len+2}} " f"{balance: <{bal_len + 5}} " f"<<{author.display_name}>>\n") if pos % 10 == 0: if embed_requested: embed = base_embed.copy() embed.description = box(temp_msg, lang="md") embed.set_footer(text=footer_message.format( page_num=len(highscores) + 1, page_len=ceil(len(bank_sorted) / 10), )) highscores.append(embed) else: highscores.append(box(temp_msg, lang="md")) temp_msg = header pos += 1 if temp_msg != header: if embed_requested: embed = base_embed.copy() embed.description = box(temp_msg, lang="md") embed.set_footer(text=footer_message.format( page_num=len(highscores) + 1, page_len=ceil(len(bank_sorted) / 10), )) highscores.append(embed) else: highscores.append(box(temp_msg, lang="md")) if highscores: await menu( ctx, highscores, DEFAULT_CONTROLS if len(highscores) > 1 else {"\N{CROSS MARK}": close_menu}, ) else: await ctx.send(_("No balances found."))
async def serverinfo(self, ctx, details: bool = False): """ Show server information. `details`: Shows more information when set to `True`. Default to False. """ guild = ctx.guild passed = (ctx.message.created_at - guild.created_at).days created_at = _( "Created on {date}. That's over {num} days ago!").format( date=guild.created_at.strftime("%d %b %Y %H:%M"), num=humanize_number(passed), ) online = humanize_number( len([ m.status for m in guild.members if m.status != discord.Status.offline ])) total_users = humanize_number(guild.member_count) text_channels = humanize_number(len(guild.text_channels)) voice_channels = humanize_number(len(guild.voice_channels)) if not details: data = discord.Embed(description=created_at, colour=await ctx.embed_colour()) data.add_field(name=_("Region"), value=str(guild.region)) data.add_field(name=_("Users online"), value=f"{online}/{total_users}") data.add_field(name=_("Text Channels"), value=text_channels) data.add_field(name=_("Voice Channels"), value=voice_channels) data.add_field(name=_("Roles"), value=humanize_number(len(guild.roles))) data.add_field(name=_("Owner"), value=str(guild.owner)) data.set_footer( text=_("Server ID: ") + str(guild.id) + _(" • Use {command} for more info on the server.").format( command=f"{ctx.clean_prefix}serverinfo 1")) if guild.icon_url: data.set_author(name=guild.name, url=guild.icon_url) data.set_thumbnail(url=guild.icon_url) else: data.set_author(name=guild.name) else: def _size(num: int): for unit in ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB"]: if abs(num) < 1024.0: return "{0:.1f}{1}".format(num, unit) num /= 1024.0 return "{0:.1f}{1}".format(num, "YB") def _bitsize(num: int): for unit in ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB"]: if abs(num) < 1000.0: return "{0:.1f}{1}".format(num, unit) num /= 1000.0 return "{0:.1f}{1}".format(num, "YB") shard_info = (_("\nShard ID: **{shard_id}/{shard_count}**").format( shard_id=humanize_number(guild.shard_id + 1), shard_count=humanize_number(ctx.bot.shard_count), ) if ctx.bot.shard_count > 1 else "") # Logic from: https://github.com/TrustyJAID/Trusty-cogs/blob/master/serverstats/serverstats.py#L159 online_stats = { _("Humans: "): lambda x: not x.bot, _(" • Bots: "): lambda x: x.bot, "\N{LARGE GREEN CIRCLE}": lambda x: x.status is discord.Status.online, "\N{LARGE ORANGE CIRCLE}": lambda x: x.status is discord.Status.idle, "\N{LARGE RED CIRCLE}": lambda x: x.status is discord.Status.do_not_disturb, "\N{MEDIUM WHITE CIRCLE}\N{VARIATION SELECTOR-16}": lambda x: (x.status is discord.Status.offline), "\N{LARGE PURPLE CIRCLE}": lambda x: any(a.type is discord.ActivityType.streaming for a in x.activities), "\N{MOBILE PHONE}": lambda x: x.is_on_mobile(), } member_msg = _( "Users online: **{online}/{total_users}**\n").format( online=online, total_users=total_users) count = 1 for emoji, value in online_stats.items(): try: num = len([m for m in guild.members if value(m)]) except Exception as error: print(error) continue else: member_msg += f"{emoji} {bold(humanize_number(num))} " + ( "\n" if count % 2 == 0 else "") count += 1 vc_regions = { "vip-us-east": _("__VIP__ US East ") + "\U0001F1FA\U0001F1F8", "vip-us-west": _("__VIP__ US West ") + "\U0001F1FA\U0001F1F8", "vip-amsterdam": _("__VIP__ Amsterdam ") + "\U0001F1F3\U0001F1F1", "eu-west": _("EU West ") + "\U0001F1EA\U0001F1FA", "eu-central": _("EU Central ") + "\U0001F1EA\U0001F1FA", "europe": _("Europe ") + "\U0001F1EA\U0001F1FA", "london": _("London ") + "\U0001F1EC\U0001F1E7", "frankfurt": _("Frankfurt ") + "\U0001F1E9\U0001F1EA", "amsterdam": _("Amsterdam ") + "\U0001F1F3\U0001F1F1", "us-west": _("US West ") + "\U0001F1FA\U0001F1F8", "us-east": _("US East ") + "\U0001F1FA\U0001F1F8", "us-south": _("US South ") + "\U0001F1FA\U0001F1F8", "us-central": _("US Central ") + "\U0001F1FA\U0001F1F8", "singapore": _("Singapore ") + "\U0001F1F8\U0001F1EC", "sydney": _("Sydney ") + "\U0001F1E6\U0001F1FA", "brazil": _("Brazil ") + "\U0001F1E7\U0001F1F7", "hongkong": _("Hong Kong ") + "\U0001F1ED\U0001F1F0", "russia": _("Russia ") + "\U0001F1F7\U0001F1FA", "japan": _("Japan ") + "\U0001F1EF\U0001F1F5", "southafrica": _("South Africa ") + "\U0001F1FF\U0001F1E6", "india": _("India ") + "\U0001F1EE\U0001F1F3", "dubai": _("Dubai ") + "\U0001F1E6\U0001F1EA", "south-korea": _("South Korea ") + "\U0001f1f0\U0001f1f7", } verif = { "none": _("0 - None"), "low": _("1 - Low"), "medium": _("2 - Medium"), "high": _("3 - High"), "extreme": _("4 - Extreme"), } features = { "ANIMATED_ICON": _("Animated Icon"), "BANNER": _("Banner Image"), "COMMERCE": _("Commerce"), "COMMUNITY": _("Community"), "DISCOVERABLE": _("Server Discovery"), "FEATURABLE": _("Featurable"), "INVITE_SPLASH": _("Splash Invite"), "MEMBER_LIST_DISABLED": _("Member list disabled"), "MEMBER_VERIFICATION_GATE_ENABLED": _("Membership Screening enabled"), "MORE_EMOJI": _("More Emojis"), "NEWS": _("News Channels"), "PARTNERED": _("Partnered"), "PREVIEW_ENABLED": _("Preview enabled"), "PUBLIC_DISABLED": _("Public disabled"), "VANITY_URL": _("Vanity URL"), "VERIFIED": _("Verified"), "VIP_REGIONS": _("VIP Voice Servers"), "WELCOME_SCREEN_ENABLED": _("Welcome Screen enabled"), } guild_features_list = [ f"\N{WHITE HEAVY CHECK MARK} {name}" for feature, name in features.items() if feature in guild.features ] joined_on = _( "{bot_name} joined this server on {bot_join}. That's over {since_join} days ago!" ).format( bot_name=ctx.bot.user.name, bot_join=guild.me.joined_at.strftime("%d %b %Y %H:%M:%S"), since_join=humanize_number( (ctx.message.created_at - guild.me.joined_at).days), ) data = discord.Embed( description=(f"{guild.description}\n\n" if guild.description else "") + created_at, colour=await ctx.embed_colour(), ) data.set_author( name=guild.name, icon_url= "https://cdn.discordapp.com/emojis/457879292152381443.png" if "VERIFIED" in guild.features else "https://cdn.discordapp.com/emojis/508929941610430464.png" if "PARTNERED" in guild.features else discord.Embed.Empty, ) if guild.icon_url: data.set_thumbnail(url=guild.icon_url) data.add_field(name=_("Members:"), value=member_msg) data.add_field( name=_("Channels:"), value=_("\N{SPEECH BALLOON} Text: {text}\n" "\N{SPEAKER WITH THREE SOUND WAVES} Voice: {voice}"). format(text=bold(text_channels), voice=bold(voice_channels)), ) data.add_field( name=_("Utility:"), value=_( "Owner: {owner}\nVoice region: {region}\nVerif. level: {verif}\nServer ID: {id}{shard_info}" ).format( owner=bold(str(guild.owner)), region= f"**{vc_regions.get(str(guild.region)) or str(guild.region)}**", verif=bold(verif[str(guild.verification_level)]), id=bold(str(guild.id)), shard_info=shard_info, ), inline=False, ) data.add_field( name=_("Misc:"), value= _("AFK channel: {afk_chan}\nAFK timeout: {afk_timeout}\nCustom emojis: {emoji_count}\nRoles: {role_count}" ).format( afk_chan=bold(str(guild.afk_channel)) if guild.afk_channel else bold(_("Not set")), afk_timeout=bold( humanize_timedelta(seconds=guild.afk_timeout)), emoji_count=bold(humanize_number(len(guild.emojis))), role_count=bold(humanize_number(len(guild.roles))), ), inline=False, ) if guild_features_list: data.add_field(name=_("Server features:"), value="\n".join(guild_features_list)) if guild.premium_tier != 0: nitro_boost = _( "Tier {boostlevel} with {nitroboosters} boosts\n" "File size limit: {filelimit}\n" "Emoji limit: {emojis_limit}\n" "VCs max bitrate: {bitrate}").format( boostlevel=bold(str(guild.premium_tier)), nitroboosters=bold( humanize_number(guild.premium_subscription_count)), filelimit=bold(_size(guild.filesize_limit)), emojis_limit=bold(str(guild.emoji_limit)), bitrate=bold(_bitsize(guild.bitrate_limit)), ) data.add_field(name=_("Nitro Boost:"), value=nitro_boost) if guild.splash: data.set_image(url=guild.splash_url_as(format="png")) data.set_footer(text=joined_on) await ctx.send(embed=data)
async def slot_machine(author, channel, bid): default_reel = deque(cast(Iterable, SMReel)) reels = [] for i in range(3): default_reel.rotate(random.randint(-999, 999)) # weeeeee new_reel = deque(default_reel, maxlen=3) # we need only 3 symbols reels.append(new_reel) # for each reel rows = ( (reels[0][0], reels[1][0], reels[2][0]), (reels[0][1], reels[1][1], reels[2][1]), (reels[0][2], reels[1][2], reels[2][2]), ) slot = "~~\n~~" # Mobile friendly for i, row in enumerate(rows): # Let's build the slot to show sign = " " if i == 1: sign = ">" slot += "{}{} {} {}\n".format( sign, *[c.value for c in row] # pylint: disable=no-member ) payout = PAYOUTS.get(rows[1]) if not payout: # Checks for two-consecutive-symbols special rewards payout = PAYOUTS.get((rows[1][0], rows[1][1]), PAYOUTS.get((rows[1][1], rows[1][2]))) if not payout: # Still nothing. Let's check for 3 generic same symbols # or 2 consecutive symbols has_three = rows[1][0] == rows[1][1] == rows[1][2] has_two = (rows[1][0] == rows[1][1]) or (rows[1][1] == rows[1][2]) if has_three: payout = PAYOUTS["3 symbols"] elif has_two: payout = PAYOUTS["2 symbols"] pay = 0 if payout: then = await bank.get_balance(author) pay = payout["payout"](bid) now = then - bid + pay try: await bank.set_balance(author, now) except errors.BalanceTooHigh as exc: await bank.set_balance(author, exc.max_balance) await channel.send( _("You've reached the maximum amount of {currency}! " "Please spend some more \N{GRIMACING FACE}\n{old_balance} -> {new_balance}!" ).format( currency=await bank.get_currency_name( getattr(channel, "guild", None)), old_balance=humanize_number(then), new_balance=humanize_number(exc.max_balance), )) return phrase = T_(payout["phrase"]) else: then = await bank.get_balance(author) await bank.withdraw_credits(author, bid) now = then - bid phrase = _("Nothing!") await channel.send(("{slot}\n{author.mention} {phrase}\n\n" + _( "Your bid: {bid}" ) + _( "\n{old_balance} - {bid} (Your bid) + {pay} (Winnings) → {new_balance}!" )).format( slot=slot, author=author, phrase=phrase, bid=humanize_number(bid), old_balance=humanize_number(then), new_balance=humanize_number(now), pay=humanize_number(pay), ))