async def convert(self, ctx, argument) -> int: try: argument = int(argument) except ValueError: raise BadArgument("The provided input must be a number.") if argument == -1: return argument if argument < -1: raise BadArgument("You must provide a number greater than -1.") return max(min(100, argument), 0)
async def convert(self, ctx: commands.Context, argument: str) -> dict: query = {} argument = argument.replace("🧑🎨", ":artist:") # because discord will replace this in URI's automatically 🙄 rec_str = r"|".join(i for i in VALID_RECOMMENDATIONS.keys()) find_rec = re.compile(fr"({rec_str})\W(.+)", flags=re.I) if not ctx.cog.GENRES: try: ctx.cog.GENRES = await ctx.cog._spotify_client.recommendation_genre_seeds( ) except Exception: raise BadArgument( _("The bot owner needs to set their Spotify credentials " "before this command can be used." " See `{prefix}spotify set creds` for more details."). format(prefix=ctx.clean_prefix)) genre_str = r"|".join(i for i in ctx.cog.GENRES) find_genre = re.compile(fr"\b({genre_str})\b", flags=re.I) find_extra = find_rec.finditer(argument) genres = list(find_genre.findall(argument)) song_data = SPOTIFY_RE.finditer(argument) tracks: List[str] = [] artists: List[str] = [] if song_data: for match in song_data: if match.group(2) == "track": tracks.append(match.group(3)) if match.group(2) == "artist": artists.append(match.group(3)) query = { "artist_ids": artists if artists else None, "genres": genres if genres else None, "track_ids": tracks if tracks else None, "limit": 100, "market": "from_token", } for match in find_extra: try: num_or_str = match.group(2).isdigit() if num_or_str: result = VALID_RECOMMENDATIONS[match.group(1)](int( match.group(2))) else: result = VALID_RECOMMENDATIONS[match.group(1)]( match.group(2)) query[f"target_{match.group(1)}"] = result except Exception: log.exception("cannot match") continue if not any([query[k] for k in ["artist_ids", "genres", "track_ids"]]): raise BadArgument( _("You must provide either an artist or track seed or a genre for this to work" )) return query
async def convert(self, ctx: commands.Context, argument: str) -> StarboardEntry: cog = ctx.cog guild = ctx.guild if guild.id not in cog.starboards: raise BadArgument( _("There are no starboards setup on this server!")) try: starboard = cog.starboards[guild.id][argument.lower()] except KeyError: raise BadArgument( _("There is no starboard named {name}").format(name=argument)) return starboard
async def convert(self, ctx, argument): result = None if argument.isdigit(): if int(argument) > 118 or int(argument) < 1: raise BadArgument("`{}` is not a valid element!".format(argument)) result = ELEMENTS(int(argument)) else: try: result = ELEMENTS(argument.title()) except Exception: raise BadArgument("`{}` is not a valid element!".format(argument)) if not result: raise BadArgument("`{}` is not a valid element!".format(argument)) return result
async def detect_file(self, ctx): if ctx.message.attachments: file = ctx.message.attachments[0].url if not file.endswith(".txt"): raise BadArgument(".txt files only") try: content = await http.get(file, no_cache=True) except Exception: raise BadArgument("Invalid .txt file") if not content: raise BadArgument("File you've provided is empty") return content
async def convert(self, ctx, argument): attachments = ctx.message.attachments mentions = MENTION_REGEX.finditer(argument) matches = IMAGE_LINKS.finditer(argument) ids = ID_REGEX.finditer(argument) urls = [] if matches: for match in matches: urls.append(match.group(1)) if mentions: for mention in mentions: user = ctx.guild.get_member(int(mention.group(1))) if user is not None: if user.is_avatar_animated(): url = IMAGE_LINKS.search(str(user.avatar_url_as(format="gif"))) urls.append(url.group(1)) else: url = IMAGE_LINKS.search(str(user.avatar_url_as(format="png"))) urls.append(url.group(1)) if not urls and ids: for possible_id in ids: user = ctx.guild.get_member(int(possible_id.group(0))) if user: if user.is_avatar_animated(): url = IMAGE_LINKS.search(str(user.avatar_url_as(format="gif"))) urls.append(url.group(1)) else: url = IMAGE_LINKS.search(str(user.avatar_url_as(format="png"))) urls.append(url.group(1)) if attachments: for attachment in attachments: urls.append(attachment.url) if not urls: if ctx.guild: user = ctx.guild.get_member_named(argument) if user: if user.is_avatar_animated(): url = user.avatar_url_as(format="gif") urls.append(url) else: url = user.avatar_url_as(format="png") urls.append(url) else: raise BadArgument("No images provided.") if not urls: raise BadArgument("No images provided.") return urls[0]
async def set_text_pageable(self, *, embed_name: str, field_title: str, pages: t.List[str], author: discord.Member = None, channel: discord.TextChannel, timeout: int = 60): if not isinstance(pages, t.List): pages = [pages] if not all(isinstance(p, str) for p in pages): raise BadArgument( 'All paginate text pages need to be of type string') embed = discord.Embed(title=embed_name, color=Colors.ClemsonOrange) # set the first page of the embed embed.add_field(name=field_title, value=pages[0]) embed.set_footer(text=f'Page 1 of {len(pages)}') msg = await channel.send(embed=embed) # stores the message info message = Message(pages, 0, author.id if author else None, embed_name=embed_name, field_title=field_title) self.messages[msg.id] = message await self.send_scroll_reactions(msg, author, timeout)
async def convert(self, ctx: commands.Context, argument: str): guild = ctx.guild result = None id_match = self._get_id_match(argument) channel_match = re.match(r"<#([0-9]+)>$", argument) member_match = re.match(r"<@!?([0-9]+)>$", argument) role_match = re.match(r"<@&([0-9]+)>$", argument) for converter in ["channel", "role", "member"]: if converter == "channel": match = id_match or channel_match if match: channel_id = match.group(1) result = guild.get_channel(int(channel_id)) else: result = discord.utils.get(guild.text_channels, name=argument) if converter == "member": match = id_match or member_match if match: member_id = match.group(1) result = guild.get_member(int(member_id)) else: result = guild.get_member_named(argument) if converter == "role": match = id_match or role_match if match: role_id = match.group(1) result = guild.get_role(int(role_id)) else: result = discord.utils.get(guild._roles.values(), name=argument) if result: break if not result: msg = _("{arg} is not a valid channel, user or role.").format(arg=argument) raise BadArgument(msg) return result
def convert(self): message = self.ctx.message bot = self.ctx.bot match = self._get_id_match() or re.match(r'<@!?([0-9]+)>$', self.argument) server = message.server result = None if match is None: # not a mention... if server: result = server.get_member_named(self.argument) if result is None: result = _get_from_servers(bot, 'get_member_named', self.argument) else: user_id = match.group(1) if server: result = server.get_member(user_id) if result is None: result = _get_from_servers(bot, 'get_member', user_id) if result is None: raise BadArgument('User "{}" not found'.format(self.argument)) return result
async def convert(self, ctx: commands.Context, argument: str) -> List[discord.Member]: bot = ctx.bot match = self._get_id_match(argument) or re.match(r"<@!?([0-9]+)>$", argument) guild = ctx.guild result = [] if match is None: # Not a mention if guild: for m in process.extract( argument, {m: unidecode(m.name) for m in guild.members}, limit=None, score_cutoff=75, ): result.append(m[2]) for m in process.extract( argument, {m: unidecode(m.nick) for m in guild.members if m.nick and m not in result}, limit=None, score_cutoff=75, ): result.append(m[2]) else: user_id = int(match.group(1)) if guild: result.append(guild.get_member(user_id)) else: result.append(_get_from_guilds(bot, "get_member", user_id)) if not result or result == [None]: raise BadArgument('Member "{}" not found'.format(argument)) return result
def get_item_id(cls, ctx, item_code: int): if item_code < 0 or item_code >= len(items): raise BadArgument( f"item_id must be an integer in the range of 0 and {len(items)}" ) item = list(items.keys())[item_code] return cls(ctx.cog.bot, item, items[item])
async def convert(self, ctx: commands.Context, argument: str) -> re.Match: match = SPOTIFY_RE.match(argument) if not match: raise BadArgument( _("{argument} is not a valid Spotify URL or URI.").format( argument=argument)) return match
async def convert(self, ctx: commands.Context, argument: str) -> str: valid_types = [ "user-read-private", "user-top-read", "user-read-recently-played", "user-follow-read", "user-library-read", "user-read-currently-playing", "user-read-playback-state", "user-read-playback-position", "playlist-read-collaborative", "playlist-read-private", "user-follow-modify", "user-library-modify", "user-modify-playback-state", "playlist-modify-public", "playlist-modify-private", "ugc-image-upload", ] find = argument.lower() if find not in valid_types: raise BadArgument( _("{argument} is not a valid scope.").format( argument=argument)) return find
async def convert(self, ctx, argument): message = ctx.message channel = ctx.message.channel attachments = ctx.message.attachments mentions = ctx.message.mentions match = IMAGE_LINKS.match(argument) emoji = EMOJI_REGEX.match(argument) urls = [] if match: urls.append(match.group(1)) if emoji: ext = "gif" if argument.startswith("<a") else "png" url = "https://cdn.discordapp.com/emojis/{id}.{ext}?v=1".format( id=emoji.group(1), ext=ext) urls.append(url) if mentions: for user in mentions: if user.is_avatar_animated(): urls.append(user.avatar_url_as(format="gif")) else: urls.append(user.avatar_url_as(format="png")) if attachments: for attachment in attachments: urls.append(attachment.url) if not urls: raise BadArgument("No images provided.") return urls
async def get_user_choice(cls, ctx: Context, search_query: str, entries: List[Tuple[str]]) -> int: em = Embed(colour=cls._embed_colour,) em.set_author(name=f'{cls._track_type} search results - {search_query} - Requested by {ctx.author}') for index, entry in enumerate(entries, 1): em.add_field( name=f'{index} - {entry[0]}', value=entry[1], inline=False) search_message = await ctx.send(embed=em) ensure_future(add_numeric_reactions(search_message, len(entries))) def check(react: Reaction, user: User): return any(( react.message.id == search_message.id, user == ctx.author, react.emoji in (numeric_emoji(n) for n in range(1, 1+len(entries))) )) try: reaction, _ = await ctx.bot.wait_for('reaction_add', check=check, timeout=60) except TimeoutError: raise BadArgument("You did not choose a search result in time.") await search_message.delete() return int(reaction.emoji[0]) - 1
async def convert( self, ctx: Context, argument: str ) -> Optional[Union[List[Dict[str, dict]], str]]: result: Optional[Union[List[Dict[str, dict]], str]] = [] team_list = await check_valid_team(argument) my_perms = ctx.channel.permissions_for(ctx.guild.me) if team_list == []: raise BadArgument('Team "{}" not found'.format(argument)) if len(team_list) == 1: result = team_list[0] else: # This is just some extra stuff to correct the team picker msg = _("There's multiple teams with that name, pick one of these:\n") new_msg = None if my_perms.add_reactions and my_perms.use_external_emojis: new_msg = await ctx.send(msg) team_emojis = [ await EmojiConverter().convert(ctx, "<:" + TEAMS[team]["emoji"] + ">") for team in team_list ] log.debug(team_emojis) log.debug(team_list) pred = ReactionPredicate.with_emojis(team_emojis, message=new_msg) start_adding_reactions(new_msg, team_emojis) try: reaction, user = await ctx.bot.wait_for("reaction_add", check=pred, timeout=60) except asyncio.TimeoutError: await new_msg.edit(content=_("I guess not.")) return None else: result = team_list[pred.result] log.debug(result) else: for i, team_name in enumerate(team_list): msg += "{}: {}\n".format(i + 1, team_name) def msg_check(m): return m.author == ctx.message.author try: msg = await ctx.bot.wait_for("message", check=msg_check, timeout=60) except asyncio.TimeoutError: await new_msg.edit(content=_("I guess not.")) return None if msg.content.isdigit(): msg = int(msg.content) - 1 try: result = team_list[msg] except (IndexError, ValueError, AttributeError): pass else: return_team = None for team in team_list: if msg.content.lower() in team.lower(): return_team = team result = return_team if new_msg: await new_msg.delete() return result
async def convert(self, ctx: Context, argument: str) -> re.Match: find = YEAR_RE.search(argument) if find: return find else: raise BadArgument( _("`{arg}` is not a valid year.").format(arg=argument))
async def convert(self, ctx: Context, argument: str) -> TextChannel: bot = ctx.bot search = self._get_id_match(argument) or match(r'<#([0-9]+)>$', argument) if match is None: # not a mention if ctx.guild: result = get(ctx.guild.text_channels, name=argument) else: def check(c): return isinstance(c, TextChannel) and c.name == argument result = find(check, bot.get_all_channels()) else: channel_id = int(search.group(1)) if ctx.guild: result = ctx.guild.get_channel(channel_id) else: result = _get_from_guilds(bot, 'get_channel', channel_id) if not isinstance(result, TextChannel): raise BadArgument('Channel "{}" not found.'.format(argument)) return result
async def convert(self, ctx, argument): if argument is None: return ctx.bot.get_user(ctx.message.author.id) match = self._get_id_match(argument) or re.match( r'<@!?([0-9]+)>$', argument) result = None state = ctx._state if match is not None: user_id = int(match.group(1)) result = ctx.bot.get_user(user_id) else: arg = argument # Check if argument contains one of the following phrases if arg in ["me", "-", ".", "self"]: # Return message author's user result = ctx.bot.get_user(ctx.message.author.id) # check for discriminator if it exists if len(arg) > 5 and arg[-5] == '#': discrim = arg[-4:] name = arg[:-5] predicate = lambda u: u.name == name and u.discriminator == discrim result = discord.utils.find(predicate, state._users.values()) if result is not None: return result predicate = lambda u: u.name == arg result = discord.utils.find(predicate, state._users.values()) if result is None: raise BadArgument('User "{}" not found'.format(argument)) return result
async def convert(self, ctx: commands.Context, argument: str) -> str: possible_results = { "allpvp": {"code": "allPvP", "alt": ["pvp"]}, "patrol": {"code": "patrol", "alt": []}, "raid": {"code": "raid", "alt": ["all"]}, "story": {"code": "story", "alt": []}, "allstrikes": {"code": "allStrikes", "alt": ["strikes", "strike"]}, "allpve": {"code": "allPvE", "alt": ["pve"]}, "allpvecompetitive": {"code": "allPvECompetitive", "alt": ["gambit"]}, } result = None argument = argument.lower() if argument in possible_results: result = possible_results[argument]["code"] else: for k, v in possible_results.items(): if argument in v["alt"]: result = v["code"] if not result: raise BadArgument( _("That is not an available stats page, pick from these: {activity_list}").format( activity_list=humanize_list(list(possible_results.keys())) ) ) return result
async def convert(self, ctx, argument): bot = ctx.bot match = self._get_id_match(argument) or re.match( r'<@!?([0-9]+)>$', argument) guild = ctx.guild result = None if match is None: # not a mention... if guild: result = guild.get_member_named(argument) else: result = _get_from_guilds(bot, 'get_member_named', argument) else: user_id = int(match.group(1)) if guild: result = guild.get_member(user_id) else: result = _get_from_guilds(bot, 'get_member', user_id) if urlparse(argument).scheme in ["http", "https"]: result = argument if result is None: raise BadArgument( f"{argument} is neither a Member nor a valid URL") return result
async def set_embed_pageable(self, *, pages: t.List[discord.Embed], author: discord.Member = None, channel: discord.TextChannel, timeout: int = 60): if not isinstance(pages, t.List): pages = [pages] if not all(isinstance(p, discord.Embed) for p in pages): raise BadArgument( 'All paginate embed pages need to be of type discord.Embed') pages[0].set_footer(text=f'Page 1 of {len(pages)}') # send the first initial embed msg = await channel.send(embed=pages[0]) await self.bot.messenger.publish(Events.on_set_deletable, msg=msg, author=msg.author) # stores the message info message = Message(pages, 0, author.id if author else None) self.messages[msg.id] = message await self.send_scroll_reactions(msg, author, timeout)
def point_range(argument) -> typing.Optional[list]: if '-' in argument: argument = argument.split('-') if len(argument) != 2: raise BadArgument('Too many -, invalid range') try: point_high = int(argument[0]) point_low = int(argument[1]) return [point_high, point_low] except ValueError as e: raise BadArgument('Point values are not an integer') try: point_high = point_low = int(argument) return [point_high, point_low] except ValueError as e: raise BadArgument('Point value is not an integer')
async def convert(self, ctx: Context, duration: str) -> t.Union[int, float]: """ Convert a `duration` string into a relativedelta using super `TimeDelta` converter. After that, simply change the relative delta into the amount of seconds it represents. Accepted inputs (in order): * infinity inputs: `-1`, `inf`, `infinity`, `infinite` * zero inputs: `0`, `none`, `null` * `TimeDelta` converter inputs """ duration = duration.lower() if duration in ["-1", "inf", "infinite", "infinity"]: return float("inf") if duration in ["0", "none", "null"]: return 0 delta = await super().convert(ctx, duration) now = datetime.utcnow() try: diff = (now + delta) - now except ValueError: raise BadArgument("Specified duration is outside maximum range.") return diff.total_seconds()
async def convert(self, ctx, argument) -> List[discord.Member]: bot = ctx.bot match = self._get_id_match(argument) or re.match(r"<@!?([0-9]+)>$", argument) guild = ctx.guild result = [] if match is None: # Not a mention if guild: for m in guild.members: if argument.lower() in unidecode.unidecode(m.display_name.lower()): # display_name so we can get the nick of the user first # without being NoneType and then check username if that matches # what we're expecting result.append(m) continue if argument.lower() in unidecode.unidecode(m.name.lower()): result.append(m) continue else: user_id = int(match.group(1)) if guild: result.append(guild.get_member(user_id)) else: result.append(_get_from_guilds(bot, "get_member", user_id)) if not result: raise BadArgument('Member "{}" not found'.format(argument)) return result
def strip_options(self, result: Dict[str, Union[List[str], str, bool, timedelta]], argument: str): possible_options = OPTIONS_RE.match(argument) if not possible_options: raise BadArgument("You have no options for this poll.") options = [ s.strip() for s in SPLIT_RE.split(possible_options[0]) if s.strip() ] if len(options) > 20: raise BadArgument( "Use less options for the poll. Max options: 20.") result["options"] = options no_options = OPTIONS_RE.sub("", argument) return result, no_options
async def search_for_images( self, ctx: commands.Context ) -> List[Union[discord.Asset, discord.Attachment, str]]: urls = [] if not ctx.channel.permissions_for(ctx.me).read_message_history: raise BadArgument("I require read message history perms to find images.") async for message in ctx.channel.history(limit=10): if message.attachments: for attachment in message.attachments: urls.append(attachment) match = IMAGE_LINKS.match(message.content) if match: urls.append(match.group(1)) if not urls: raise BadArgument("No Images found in recent history.") return urls
async def convert(self, ctx, argument): match = self._get_id_match(argument) or re.match( r'<@!?([0-9]+)>$', argument) guild = ctx.guild result = None user_id = None if match is None: # not a mention... if guild: result = guild.get_member_named(argument) else: user_id = int(match.group(1)) if guild: result = guild.get_member(user_id) or discord.utils.get( ctx.message.mentions, id=user_id) if result is None and guild and user_id: try: _message_cache[guild.id]["users"][user_id] except KeyError: pass else: result = CacheUser(_id=user_id, guild=guild) if result is None: raise BadArgument( "User not found in the guild nor in the recorded messages.") return result
async def detect_file(ctx): print(ctx.message.attachments) if ctx.message.attachments: file = ctx.message.attachments[0].url if not file.endswith(".txt"): raise BadArgument("只接受txt檔") else: raise try: content = await http.get(file, no_cache=True) except Exception: raise BadArgument("無效的txt檔") if not content: raise BadArgument("你提供的檔案是空的") return content
def parse_gimme(argument) -> typing.Optional[str]: keywords = [ 'adhoc', 'Ad Hoc', 'math', 'Advanced Math', 'Intermediate Math', 'Simple Math', 'bf', 'Brute Force', 'ctf', 'Capture the Flag', 'ds', 'Data Structures', 'd&c', 'Divide and Conquer', 'dp', 'Dynamic Programming', 'geo', 'Geometry', 'gt', 'Graph Theory', 'greedy', 'Greedy Algorithms', 'regex', 'Regular Expressions', 'string', 'String Algorithms' ] if argument in keywords: raise BadArgument("Argument is keyword") try: print(point_range(argument)) except BadArgument: return argument.replace('\'', '') raise BadArgument("Argument is point range")