def rate_limits_and_misc(): misc_config = Config("misc.json") cooldown_coeffs = misc_config.get("cooldown_coeffs") for chan_id, value in cooldown_coeffs.items(): rconfig.set("chan:{}:rate_limits:cooldown_ratio".format(chan_id), float(value)) counters = misc_config.get("counters")["Porygon2"] for command, uses in counters.items(): rconfig.zadd("misc:rate_limits:counters", int(uses), command)
class MemeGenerator: pattern = re.compile(r'(\w+)\s+(.*)$') def __init__(self, bot): self.bot = bot self.conf = Config('configs/memes.json') doc = self.meme.__dict__['help'] doc += '\n ' doc += '\n '.join(self.conf.get('memes', {}).keys()) self.meme.__dict__['help'] = doc @commands.command(pass_context=True, aliases=['memes']) async def meme(self, ctx, *, text: str): """ Adds text to images Valid names so far: """ match = MemeGenerator.pattern.match(text) name = match.group(1).lower() text = match.group(2) text = ' '.join(dh.remove_comments(text.split())) cfg = self.conf.get('memes', {}).get(name, None) if not cfg: await self.bot.say(error('Could not find image')) return if not text: await self.bot.say(error('Are you trying to get an empty image?')) return temp = tempfile.NamedTemporaryFile(suffix=".png") if 'font' not in cfg: cfg['font'] = self.conf.get('font', '') if 'path' not in cfg: cfg['path'] = self.conf.get('path', '') write_image(text, temp.name, **cfg) await self.bot.send_file(ctx.message.channel, temp.name) temp.close()
async def on_message(message): if message.author.bot: return perms = Config('configs/perms.json') if message.author.id in perms.get('ignore', []): return if not re.search('^[\\.!\\?\\$]{2,}', message.content): await bot.process_commands(message)
def friend_codes(): fc_config = Config("friend_codes.json") for user_id in fc_config: fc_info = fc_config.get(user_id) for key, val in fc_info.items(): if key in ["3DS", "Switch"]: rconfig.set("user:{}:fc:{}:code".format(user_id, key), val) elif "ign" in key: if "3DS" in key: rconfig.hmset("user:{}:fc:3DS:ign".format(user_id), val) # pretty sure I only support 3ds
class Games: def __init__(self, bot): self.bot = bot self.conf = Config('configs/games.json') @perms.is_owner() @commands.command(pass_context=True, aliases=['faa']) async def fake_artist_add(self, ctx, *, themes): self.conf['fake_artist']['themes'].extend(themes.strip().split('\n')) self.conf.save() await self.bot.say(formatter.ok()) @commands.command(pass_context=True, aliases=['fa']) async def fake_artist(self, ctx, number: int): conf = self.conf.get('fake_artist', {}) themes = conf.get('themes', []) themes = random.sample(themes, len(themes) - len(themes) % number) output = [[] for i in range(number)] fakes = list(range(number)) * (len(themes) // number) random.shuffle(fakes) say = 'here are the links:' # generate for theme, fake in zip(themes, fakes): for i in range(len(output)): output[i].append(theme if i != fake else 'YOU ARE THE FAKE') # generate master file with open(os.path.join(conf.get('path', ''), 'master.html'), 'w') as f: f.write(conf.get('rules')) for i, theme in enumerate(themes): f.write(f'''<li><input class="spoilerbutton" type="button"'''+ \ f'''value="show" onclick="this.value=this.value=='show'''+ \ f'''\'?'{html.escape(theme)}':'show';"></li>''') f.write(conf.get('out')) # generate player files for i in range(len(output)): filename = os.path.join(conf.get('path', ''), f'{i+1}.html') with open(filename, 'w') as f: f.write(conf.get('rules')) for theme in output[i]: f.write(f'<li>{html.escape(theme)}</li>') f.write(conf.get('out')) say += f'\nhttps://andy29485.tk/files/{i+1}.html' await self.bot.say(formatter.ok(say))
class Yuna(commands.AutoShardedBot): def __init__(self): super().__init__(command_prefix=get_prefix) self.session = aiohttp.ClientSession(loop=self.loop) self._prev_events = deque(maxlen=10) self.commands_run = 0 self.prefixes = Config('prefixes.json') self.remove_command('help') self.add_command(self._help) for extension in INITIAL_EXTENSIONS: try: self.load_extension(f'cogs.{extension}') print(f'[INFO] Loaded {extension}') except Exception as e: print(f'[FAIL] Failed to load {extension} with error: {e}') @property def config(self): import config as _cfg return _cfg @commands.command(name='help', hidden=True) async def _help(self, ctx, *, command: str = None): """Shows help about a command or the bot""" try: if command is None: p = await HelpPaginator.from_bot(ctx) else: entity = self.get_cog(command) or self.get_command(command) if entity is None: clean = command.replace('@', '@\u200b') return await ctx.send( f'Command or category "{clean}" not found.') elif isinstance(entity, commands.Command): p = await HelpPaginator.from_command(ctx, entity) else: p = await HelpPaginator.from_cog(ctx, entity) await p.paginate() except Exception as e: await ctx.send(e) @property def config(self): """Returns the config.""" return __import__('config') async def avatar_queue(self): try: avatars = [ 'https://cdn.discordapp.com/attachments/488928330805018626/492776771662643200/maxresdefault.png?width=734&height=413', 'https://media.discordapp.net/attachments/488928330805018626/492777747941163009/image0.png?width=660&height=413', 'https://media.discordapp.net/attachments/488928330805018626/492776959588433928/878577-download-wallpaper-yuna-1961x1226-pc.png?width=660&height=413' ] while True: r = requests.get(rnd(avatars)) await self.user.edit(avatar=r.content) await asyncio.sleep(86400) except Exception as e: print(e) async def on_ready(self): print(f"[INFO] I'm Alive!\n"\ f"[NAME] Logged in as {self.user.name}.\n"\ f"[ ID ] {self.user.id}") await self.change_presence(activity=discord.Activity( name='y?help | UwU', type=discord.ActivityType.listening)) self.loop.create_task(self.avatar_queue()) @property def error_ch(self): ch = self.get_channel(492797168005152778) return ch @property def guild_ch(self): ch = self.get_channel(492797204873084949) return ch async def send_guild_stats(self, e, guild): e.add_field(name='Name', value=guild.name) e.add_field(name='ID', value=guild.id) e.add_field(name='Owner', value=f'{guild.owner} (ID: {guild.owner.id})') bots = sum(m.bot for m in guild.members) total = guild.member_count online = sum(m.status is discord.Status.online for m in guild.members) e.add_field(name='Members', value=str(total)) e.add_field(name='Bots', value=f'{bots} ({bots/total:.2%})') e.add_field(name='Online', value=f'{online} ({online/total:.2%})') if guild.icon: e.set_thumbnail(url=guild.icon_url) if guild.me: e.timestamp = guild.me.joined_at await self.guild_ch.send(embed=e) async def on_guild_join(self, guild): e = discord.Embed(colour=0x53dda4, title='New Guild') await self.send_guild_stats(e, guild) async def on_guild_remove(self, guild): e = discord.Embed(colour=0xdd5f53, title='Left Guild') await self.send_guild_stats(e, guild) async def on_command_error(self, ctx, error): try: ignored = (commands.NoPrivateMessage, commands.DisabledCommand, commands.CheckFailure, commands.CommandNotFound, commands.UserInputError, discord.Forbidden, commands.CommandOnCooldown) error = getattr(error, 'original', error) if isinstance(error, ignored): return e = discord.Embed(title='Command Error', colour=0xcc3366) e.add_field(name='Name', value=ctx.command.qualified_name) e.add_field(name='Author', value=f'{ctx.author} (ID: {ctx.author.id})') fmt = f'Channel: {ctx.channel} (ID: {ctx.channel.id})' if ctx.guild: fmt = f'{fmt}\nGuild: {ctx.guild} (ID: {ctx.guild.id})' e.add_field(name='Location', value=fmt, inline=False) exc = ''.join( traceback.format_exception(type(error), error, error.__traceback__, chain=False)) e.description = f'```py\n{exc}\n```' e.timestamp = datetime.datetime.utcnow() await self.error_ch.send(embed=e) except Exception as e: print(e) async def on_error(self, event, *args, **kwargs): e = discord.Embed(title='Event Error', colour=0xa32952) e.add_field(name='Event', value=event) e.description = f'```py\n{traceback.format_exc()}\n```' e.timestamp = datetime.datetime.utcnow() await self.error_ch.send(embed=e) async def on_command(self, ctx): """This triggers when a command is invoked.""" self.commands_run += 1 def get_guild_prefixes(self, guild, *, local_inject=get_prefix): """Gets the guild prefixes.""" proxy_msg = discord.Object(id=None) proxy_msg.guild = guild return local_inject(self, proxy_msg) def get_raw_guild_prefixes(self, guild_id): """Gets the raw guild prefixes.""" return self.prefixes.get(guild_id, ['.']) async def set_guild_prefixes(self, guild, prefixes): """Sets the guild prefixes.""" if not prefixes[0]: await self.prefixes.put(guild.id, []) elif len(prefixes) > 10: raise RuntimeError('Cannot have more than 10 custom prefixes.') else: await self.prefixes.put(guild.id, sorted(set(prefixes), reverse=True)) async def on_message(self, message): if message.author.bot: return await self.process_commands(message) async def on_resumed(self): """This triggers when the bot resumed after an outage.""" print('[INFO] Resumed...') async def process_commands(self, message): """This processes the commands.""" ctx = await self.get_context(message, cls=context.Context) if ctx.command is None: return async with ctx.acquire(): await self.invoke(ctx) async def close(self): await super().close() await self.session.close() def run(self): try: super().run(config.token, reconnect=True) finally: with open('prev_events.log', 'w', encoding='utf-8') as _fp: for data in self._prev_events: try: _x = json.dumps(data, ensure_ascii=True, indent=4) except: _fp.write(f'{data}\n') else: _fp.write(f'{_x}\n')
msg = ctx.message chan = None if ctx.message.channel.is_private: chan = 'PM' else: chan = '#{0.channel.name} ({0.server.name})'.format(msg) logger.info('{0.author.name} in {1}: {0.content}'.format(msg, chan)) @bot.async_event async def on_message(message): if message.author.bot: return perms = Config('configs/perms.json') if message.author.id in perms.get('ignore', []): return if not re.search('^[\\.!\\?\\$]{2,}', message.content): await bot.process_commands(message) auth = Config('configs/auth.json') while len(auth.get('token', '')) < 30: auth['token'] = input('Please enter bot\'s token: ') auth.save() #start bot bot.run(auth['token'])
class RoboDanny(commands.AutoShardedBot): def __init__(self): super().__init__(command_prefix=_prefix_callable, description=description, pm_help=None, help_attrs=dict(hidden=True), fetch_offline_members=False, heartbeat_timeout=150.0) self.client_id = config.client_id self.carbon_key = config.carbon_key self.bots_key = config.bots_key self.challonge_api_key = config.challonge_api_key self.session = aiohttp.ClientSession(loop=self.loop) self._prev_events = deque(maxlen=10) # shard_id: List[datetime.datetime] # shows the last attempted IDENTIFYs and RESUMEs self.resumes = defaultdict(list) self.identifies = defaultdict(list) # guild_id: list self.prefixes = Config('prefixes.json') # guild_id and user_id mapped to True # these are users and guilds globally blacklisted # from using the bot self.blacklist = Config('blacklist.json') # in case of even further spam, add a cooldown mapping # for people who excessively spam commands self.spam_control = commands.CooldownMapping.from_cooldown( 10, 12.0, commands.BucketType.user) # A counter to auto-ban frequent spammers # Triggering the rate limit 5 times in a row will auto-ban the user from the bot. self._auto_spam_count = Counter() for extension in initial_extensions: try: self.load_extension(extension) except Exception as e: print(f'Failed to load extension {extension}.', file=sys.stderr) traceback.print_exc() def _clear_gateway_data(self): one_week_ago = datetime.datetime.utcnow() - datetime.timedelta(days=7) for shard_id, dates in self.identifies.items(): to_remove = [ index for index, dt in enumerate(dates) if dt < one_week_ago ] for index in reversed(to_remove): del dates[index] for shard_id, dates in self.resumes.items(): to_remove = [ index for index, dt in enumerate(dates) if dt < one_week_ago ] for index in reversed(to_remove): del dates[index] async def on_socket_response(self, msg): self._prev_events.append(msg) async def before_identify_hook(self, shard_id, *, initial): self._clear_gateway_data() self.identifies[shard_id].append(datetime.datetime.utcnow()) await super().before_identify_hook(shard_id, initial=initial) async def on_command_error(self, ctx, error): if isinstance(error, commands.NoPrivateMessage): await ctx.author.send( 'This command cannot be used in private messages.') elif isinstance(error, commands.DisabledCommand): await ctx.author.send( 'Sorry. This command is disabled and cannot be used.') elif isinstance(error, commands.CommandInvokeError): original = error.original if not isinstance(original, discord.HTTPException): print(f'In {ctx.command.qualified_name}:', file=sys.stderr) traceback.print_tb(original.__traceback__) print(f'{original.__class__.__name__}: {original}', file=sys.stderr) elif isinstance(error, commands.ArgumentParsingError): await ctx.send(error) def get_guild_prefixes(self, guild, *, local_inject=_prefix_callable): proxy_msg = discord.Object(id=0) proxy_msg.guild = guild return local_inject(self, proxy_msg) def get_raw_guild_prefixes(self, guild_id): return self.prefixes.get(guild_id, ['?', '!']) async def set_guild_prefixes(self, guild, prefixes): if len(prefixes) == 0: await self.prefixes.put(guild.id, []) elif len(prefixes) > 10: raise RuntimeError('Cannot have more than 10 custom prefixes.') else: await self.prefixes.put(guild.id, sorted(set(prefixes), reverse=True)) async def add_to_blacklist(self, object_id): await self.blacklist.put(object_id, True) async def remove_from_blacklist(self, object_id): try: await self.blacklist.remove(object_id) except KeyError: pass async def on_ready(self): if not hasattr(self, 'uptime'): self.uptime = datetime.datetime.utcnow() print(f'Ready: {self.user} (ID: {self.user.id})') async def on_shard_resumed(self, shard_id): print(f'Shard ID {shard_id} has resumed...') self.resumes[shard_id].append(datetime.datetime.utcnow()) @property def stats_webhook(self): wh_id, wh_token = self.config.stat_webhook hook = discord.Webhook.partial(id=wh_id, token=wh_token, adapter=discord.AsyncWebhookAdapter( self.session)) return hook def log_spammer(self, ctx, message, retry_after, *, autoblock=False): guild_name = getattr(ctx.guild, 'name', 'No Guild (DMs)') guild_id = getattr(ctx.guild, 'id', None) fmt = 'User %s (ID %s) in guild %r (ID %s) spamming, retry_after: %.2fs' log.warning(fmt, message.author, message.author.id, guild_name, guild_id, retry_after) if not autoblock: return wh = self.stats_webhook embed = discord.Embed(title='Auto-blocked Member', colour=0xDDA453) embed.add_field(name='Member', value=f'{message.author} (ID: {message.author.id})', inline=False) embed.add_field(name='Guild Info', value=f'{guild_name} (ID: {guild_id})', inline=False) embed.add_field(name='Channel Info', value=f'{message.channel} (ID: {message.channel.id}', inline=False) embed.timestamp = datetime.datetime.utcnow() return wh.send(embed=embed) async def process_commands(self, message): ctx = await self.get_context(message, cls=context.Context) if ctx.command is None: return if ctx.author.id in self.blacklist: return if ctx.guild is not None and ctx.guild.id in self.blacklist: return bucket = self.spam_control.get_bucket(message) current = message.created_at.replace( tzinfo=datetime.timezone.utc).timestamp() retry_after = bucket.update_rate_limit(current) author_id = message.author.id if retry_after and author_id != self.owner_id: self._auto_spam_count[author_id] += 1 if self._auto_spam_count[author_id] >= 5: await self.add_to_blacklist(author_id) del self._auto_spam_count[author_id] await self.log_spammer(ctx, message, retry_after, autoblock=True) else: self.log_spammer(ctx, message, retry_after) return else: self._auto_spam_count.pop(author_id, None) try: await self.invoke(ctx) finally: # Just in case we have any outstanding DB connections await ctx.release() async def on_message(self, message): if message.author.bot: return await self.process_commands(message) async def on_guild_join(self, guild): if guild.id in self.blacklist: await guild.leave() async def close(self): await super().close() await self.session.close() def run(self): try: super().run(config.token, reconnect=True) finally: with open('prev_events.log', 'w', encoding='utf-8') as fp: for data in self._prev_events: try: x = json.dumps(data, ensure_ascii=True, indent=4) except: fp.write(f'{data}\n') else: fp.write(f'{x}\n') @property def config(self): return __import__('config')
class WBot(commands.AutoShardedBot): """Discord bot made by iWeeti#8031.""" def __init__(self): super().__init__(command_prefix=_prefix_callable, description=DESCRIPTION, fetch_offline_members=False) self.session = aiohttp.ClientSession(loop=self.loop) self.commands_executed = 0 self._prev_events = deque(maxlen=10) self.add_command(self._do) self.add_command(self.setup) self.remove_command('help') self.uptime = datetime.datetime.utcnow() self.prefixes = Config('prefixes.json') for extension in INITIAL_EXTENSIONS: try: self.load_extension(extension) print(f'[INFO] {extension} loaded.') except ModuleNotFoundError: print(f'[FAIL] Extension {extension} not found.', file=sys.stderr) except: print(f'[FAIL] Failed to load extension {extension}.', file=sys.stderr) traceback.print_exc() logger = logging.getLogger('__main__') @property def config(self): """Returns the config.""" return __import__('config') def get_guild_prefixes(self, guild, *, local_inject=_prefix_callable): """Gets the guild prefixes.""" proxy_msg = discord.Object(id=None) proxy_msg.guild = guild return local_inject(self, proxy_msg) def get_raw_guild_prefixes(self, guild_id): """Gets the raw guild prefixes.""" return self.prefixes.get(guild_id, ['.']) async def set_guild_prefixes(self, guild, prefixes): """Sets the guild prefixes.""" if not prefixes[0]: await self.prefixes.put(guild.id, []) elif len(prefixes) > 10: raise RuntimeError('Cannot have more than 10 custom prefixes.') else: await self.prefixes.put(guild.id, sorted(set(prefixes), reverse=True)) async def on_guild_join(self, guild): """This triggers when the bot joins a guild.""" game = discord.Activity(name=f"slaves in {len(self.guilds)} servers.", type=discord.ActivityType.watching) await self.change_presence(status=discord.Status.online, activity=game) if guild.id == 421630709585805312: return try: channel = await guild.create_text_channel('w-bot-logging') overwrite = discord.PermissionOverwrite(read_messages=False) role = guild.default_role await channel.set_permissions(role, overwrite=overwrite) await guild.owner.send(f'Hey, it seems that you own **{guild.name}**' ' and I have been invited to there.'\ 'Run ``.settings`` to get started.') await channel.send('To get started run ``.settings``.'\ 'If you need more info join here https://discord.gg/Ry4JQRf.' \ 'You can also check my commands by running ``.help``.') except discord.Forbidden: await guild.owner.send('Please let me have Create channels' ' permissions so you can get started.'\ 'After you have setted up the permissions, run ``.setup``.') async def on_member_join(self, member): """This triggers when someone joins a guild the bot is in.""" guild = member.guild if guild.id == 329993146651901952: role = discord.utils.get(member.guild.roles, name='Member') try: await member.add_roles(role) except discord.Forbidden: member.guild.send('I do not have proper permissions' ' or high enough rank to give roles.') else: return @property def error_ch(self): """Returns the error logging channel.""" ch = self.get_channel(491609962821451776) return ch @property def guild_ch(self): """Returns the guild logging channel.""" ch = self.get_channel(493774827610439690) return ch async def send_guild_stats(self, e, guild): e.add_field(name='Name', value=guild.name) e.add_field(name='ID', value=guild.id) e.add_field(name='Owner', value=f'{guild.owner} (ID: {guild.owner.id})') bots = sum(m.bot for m in guild.members) total = guild.member_count online = sum(m.status is discord.Status.online for m in guild.members) e.add_field(name='Members', value=str(total)) e.add_field(name='Bots', value=f'{bots} ({bots/total:.2%})') e.add_field(name='Online', value=f'{online} ({online/total:.2%})') if guild.icon: e.set_thumbnail(url=guild.icon_url) if guild.me: e.timestamp = guild.me.joined_at await self.guild_ch.send(embed=e) async def on_guild_join(self, guild): e = discord.Embed(colour=0x53dda4, title='New Guild') await self.send_guild_stats(e, guild) async def on_guild_remove(self, guild): e = discord.Embed(colour=0xdd5f53, title='Left Guild') await self.send_guild_stats(e, guild) async def on_command_error(self, ctx, error): if isinstance(error, commands.NoPrivateMessage): return await ctx.send( ctx.message.author, 'This command cannot be used in private messages.') elif isinstance(error, commands.DisabledCommand): return await ctx.send( ctx.message.author, 'Sorry. This command is disabled' ' and cannot be used.') elif isinstance(error, commands.BadArgument): return await ctx.send(error) elif isinstance(error, commands.MissingPermissions): missing_perms = error.missing_perms[0].replace('_', ' ') return await ctx.send( f'You do not have **{missing_perms}** permissions.' ' You need them to use this command.') elif isinstance(error, commands.BotMissingPermissions): missing_perms = ", ".join( _perms.replace('_', ' ') for _perms in error.missing_perms) return await ctx.send( f'You do not have **{missing_perms}** permissions.' ' You need them to use this command.') elif isinstance(error, commands.NotOwner): return await ctx.send('Only my creator can use this command.') if isinstance(error, commands.CommandOnCooldown): minutes, seconds = divmod(error.retry_after, 60) hours, minutes = divmod(minutes, 60) if hours >= 2: hours = f'{round(hours)} hours ' elif hours == 0: hours = '' else: hours = f'{round(hours)} hour ' if minutes >= 2: minutes = f'{round(minutes)} minutes ' elif minutes == 0: minutes = '' else: minutes = f'{round(minutes)} minute ' if seconds >= 2: seconds = f'{round(seconds)} seconds ' elif seconds == 0: seconds = '' else: seconds = f'{seconds} second' return await ctx.send( f'This command is on cooldown for {hours}{minutes}{seconds}.') ignored = (commands.NoPrivateMessage, commands.DisabledCommand, commands.CheckFailure, commands.CommandNotFound, commands.UserInputError, discord.Forbidden, commands.CommandOnCooldown) error = getattr(error, 'original', error) if isinstance(error, ignored): return e = discord.Embed(title='Command Error', colour=0xcc3366) e.add_field(name='Name', value=ctx.command.qualified_name) e.add_field(name='Author', value=f'{ctx.author} (ID: {ctx.author.id})') fmt = f'Channel: {ctx.channel} (ID: {ctx.channel.id})' if ctx.guild: fmt = f'{fmt}\nGuild: {ctx.guild} (ID: {ctx.guild.id})' e.add_field(name='Location', value=fmt, inline=False) exc = ''.join( traceback.format_exception(type(error), error, error.__traceback__, chain=False)) e.description = f'```py\n{exc}\n```' e.timestamp = datetime.datetime.utcnow() await self.error_ch.send(embed=e) async def on_error(self, event, *args, **kwargs): e = discord.Embed(title='Event Error', colour=0xa32952) e.add_field(name='Event', value=event) e.description = f'```py\n{traceback.format_exc()}\n```' e.timestamp = datetime.datetime.utcnow() await self.error_ch.send(embed=e) async def on_ready(self): """This triggers when the bot is ready.""" print('[INFO] Bot is online') print('[NAME] ' + self.user.name) print('[ ID ] ' + str(self.user.id)) print('[]---------------------------[]') self.commands_executed = 0 game = discord.Activity(name=f"slaves in {len(self.guilds)} servers.", type=discord.ActivityType.watching) await self.change_presence(status=discord.Status.online, activity=game) async def on_command(self, ctx): """This triggers when a command is invoked.""" self.commands_executed += 1 if isinstance(ctx.channel, discord.DMChannel): return message = ctx.message destination = '#{0.channel.name} ({0.guild.name})'.format(message) if isinstance(message.channel, discord.DMChannel): destination = '{}\'s dmchannel' logger = logging.getLogger('__main__') logger.info('{0.created_at}: {0.author.name} in {1}:' ' {0.content}'.format(message, destination)) async def on_message(self, message): """This triggers when the bot can see a message being sent.""" if not message.author.bot: # mod = self.get_cog('Mod') # if mod is not None and not message.author.id == 282515230595219456: # perms = message.channel.permissions_for(message.author) # bypass_ignore = perms.manage_roles # if not bypass_ignore: # if message.channel.id in mod.config.get('ignored', []): # return await self.process_commands(message) @commands.command(hidden=True) @commands.has_permissions(administrator=True) async def setup(self, ctx): """Sets up the logging channel.""" already = get(ctx.guild.channels, name='w-bot-logging') if already: return await ctx.send('Seems that you already have a' ' channel called ``w-bot-logging`` please' ' delete it to set me up.') channel = await ctx.guild.create_text_channel('w-bot-logging') overwrite = discord.PermissionOverwrite(read_messages=False) role = ctx.guild.default_role await channel.set_permissions(role, overwrite=overwrite) await ctx.bot.pool.execute( f'insert into settings values({ctx.guild.id}, true)') await channel.send('Alright to get started use ``.settings``.'\ 'If you want to see my commands use ``.help``.') @commands.command(hidden=True) async def shutdown(self, ctx): """Shuts down the bot.""" await ctx.send(':wave: Cya!') await self.logout() @commands.command(hidden=True) @commands.is_owner() async def _do(self, ctx, times: int, *, command): """Repeats a command a specified number of times.""" msg = copy.copy(ctx.message) msg.content = command new_ctx = await self.get_context(msg, cls=context.Context) new_ctx.db = ctx.db for i in range(times): i = i await new_ctx.reinvoke() async def on_resumed(self): """This triggers when the bot resumed after an outage.""" print('[INFO] Resumed...') async def process_commands(self, message): """This processes the commands.""" ctx = await self.get_context(message, cls=context.Context) if ctx.command is None: return async with ctx.acquire(): await self.invoke(ctx) async def on_message_edit(self, before, after): await self.process_commands(after) async def close(self): await super().close() await self.session.close() def run(self): try: super().run(config.token, reconnect=True) finally: with open('prev_events.log', 'w', encoding='utf-8') as _fp: for data in self._prev_events: try: _x = json.dumps(data, ensure_ascii=True, indent=4) except: _fp.write(f'{data}\n') else: _fp.write(f'{_x}\n')
class Server: def __init__(self, bot): self.bot = bot self.conf = Config('configs/server.json') self.heap = Config('configs/heap.json') self.cut = {} for rem in self.conf.pop('end_role', []): self.heap['heap'].push(rem) @perms.has_perms(manage_messages=True) @commands.command(name='prune', pass_context=True) async def _prune(self, ctx, num_to_delete: int, *message): """ deletes specified number of messages from channel if message is specified, message will be echoed by bot after prune USAGE: .prune <num> [user] [message...] NOTE: if first word after number is a user, only user's messages will be pruned """ # tmp channel/server pointer chan = ctx.message.channel serv = ctx.message.server #if num_to_delete > 100: # api only allows up to 100 # await self.bot.say('Sorry, only up to 100') # TODO - copy thing done in # return # self._paste if num_to_delete < 1: # delete nothing? await self.bot.say('umm... no') # answer: no return # if the first word in the message matches a user, # remove that word from the message, store the user try: user = dh.get_user(serv or self.bot, message[0]) if user: message = message[1:] except: logger.debug('did not match a user') user = None check = lambda m: True if user: # if a user was matched, delete messages for that user only logger.debug(f'pruning for user {user.name}') check = lambda m: m.author.id == user.id message = ' '.join(message) #make the message a string logs = [] async for m in self.bot.logs_from(chan, num_to_delete, reverse=True): if check(m): logs.append(m) deleted = len(logs) old = False while len(logs) > 0: # while there are messages to delete if len(logs) > 1: # if more than one left to delete and not old, if not old: # attempt batch delete [2-100] messages try: await self.bot.delete_messages(logs[:100]) except: # if problem when batch deleting old = True # then the messages must be old if old: # if old, traverse and delete individually for entry in logs[:100]: try: await self.bot.delete_message(entry) except: logger.exception( '<{0.author.name}> {0.content}'.format(entry)) logs = logs[100:] else: # if only one message, delete individually await self.bot.delete_message(logs[0]) logs.remove(logs[0]) #report that prume was complete, how many were prunned, and the message await self.bot.say( ok('Deleted {} message{} {}'.format( deleted, '' if deleted == 1 else 's', f'({message})' if message else ''))) @commands.group(name='role', aliases=['give', 'giveme', 'gimme'], pass_context=True) async def _role(self, ctx): """ Manage publicly available roles """ # if no sub commands were called, guess at what the user wanted to do if ctx.invoked_subcommand is None: msg = ctx.message.content.split() # attempt to parse args if len(msg) < 2: await self.bot.say('see help (`.help role`)') return role = msg[1] date = ' '.join(msg[2:]) # if the user cannot manage roles, then they must be requesting a role # or they are trying to do something that they are not allowed to if not perms.check_permissions(ctx.message, manage_roles=True): await self._request_wrap(ctx, role, date) # attempt to request role return #if the user does have permission to manage, they must be an admin/mod # ask them what they want to do - since they clearly did not know what # they were trying to do await self.bot.say('Are you trying to [a]dd a new role ' + \ 'or are you [r]equesting this role for yourself?' ) try: # wait for them to reply msg = await self.bot.wait_for_message( 30, author=ctx.message.author, channel=ctx.message.channel) except: # if they do not reply, give them a helpful reply # without commenting on their IQ await self.bot.say( error('Response timeout, maybe look at the help?')) return # if a reply was recived, check what they wanted to do and pass along msg = msg.content.lower() if msg.startswith('a') or 'add' in msg: # adding new role to list await self._add_wrap(ctx, role) reply = f"Please run `.role request {role}` to get the \"{role}\" role" await self.bot.say(reply) elif msg.startswith( 'r') or 'request' in msg: # requesting existing role await self._request_wrap(ctx, role, date) else: # they can't read await self.bot.say(error('I have no idea what you are attempting' + \ ' to do, maybe look at the help?') ) @_role.command(name='add', aliases=['create', 'a'], pass_context=True) @perms.has_perms(manage_roles=True) async def _add(self, ctx, role: str): """ adds role to list of public roles """ await self._add_wrap(ctx, role) @_role.command(name='list', aliases=['ls', 'l'], pass_context=True) async def _list(self, ctx): """ lists public roles avalible in the server """ # pull roles out of the config file serv = ctx.message.server names = [] m_len = 0 available_roles = self.conf.get(serv.id, {}).get('pub_roles', []) # if no roles, say so if not available_roles: await self.bot.say('no public roles in this server\n' + \ ' see `.help role create` and `.help role add`' ) return # For each id in list # find matching role in server # if role exists, add it to the role list # Note: this block also finds the strlen of the longest role name, # this will be used later for formatting for role_id in available_roles: role = discord.utils.find(lambda r: r.id == role_id, serv.roles) if role: names.append(role.name) m_len = max(m_len, len(role.name)) # create a message with each role name and id on a seperate line # seperators(role - id) should align due to spacing - this is what the # lenght of the longest role name is used for msg = 'Roles:\n```' line = '{{:{}}} - {{}}\n'.format(m_len) for name, rid in zip(names, available_roles): msg += line.format(name, rid) # send message with role list await self.bot.say(msg + '```') @_role.command(name='remove', aliases=['rm'], pass_context=True) @perms.has_perms(manage_roles=True) async def _delete(self, ctx, role: str): """ removes role from list of public roles """ # attempt to find specified role and get list of roles in server serv = ctx.message.server role = dh.get_role(serv, role) available_roles = self.conf.get(serv.id, {}).get('pub_roles', []) # if user failed to specify role, complain if not role: await self.bot.say('Please specify a valid role') return if serv.id not in self.conf: self.conf[serv.id] = {'pub_roles': []} self.conf.save() elif 'pub_roles' not in self.conf[serv.id]: self.conf[serv.id]['pub_roles'] = [] self.conf.save() if role.id in available_roles: # if role is found, remove and report self.conf[serv.id]['pub_roles'].remove(role.id) self.conf.save() await self.bot.say(ok('role removed from public list')) else: # if role is not in server, just report await self.bot.say(error('role is not in the list')) @_role.command(name='request', aliases=['r'], pass_context=True) async def _request(self, ctx, role: str, date: str = ''): """ adds role to requester(if in list) """ await self._request_wrap(ctx, role, date) @_role.command(name='unrequest', aliases=['rmr', 'u'], pass_context=True) async def _unrequest(self, ctx, role: str): """removes role from requester(if in list)""" # attempt to find role that user specied for removal auth = ctx.message.author serv = ctx.message.server role = dh.get_role(serv, role) # if user failed to find specify role, complain if not role: await self.bot.say('Please specify a valid role') return # get a list of roles that are listed as public and the user roles available_roles = self.conf.get(serv.id, {}).get('pub_roles', []) user_roles = discord.utils.find(lambda r: r.id == role.id, auth.roles) # ONLY remove roles if they are in the public roles list # Unless there is no list, # in which case any of the user's roles can be removed if role.id in available_roles or user_roles: await self.bot.remove_roles(auth, role) await self.bot.say(ok('you no longer have that role')) else: await self.bot.say( error('I\'m afraid that I can\'t remove that role')) # wrapper function for adding roles to public list async def _add_wrap(self, ctx, role): serv = ctx.message.server # find the role, # if it is not found, create a new role role_str = role if type(role) != discord.Role: role = dh.get_role(serv, role_str) if not role: role = await self.bot.create_role(serv, name=role_str, mentionable=True) await self.bot.say(ok(f'New role created: {role_str}')) # if still no role, report and stop if not role: await self.bot.say(error("could not find or create role role")) return # The @everyone role (also @here iiuc) cannot be given/taken if role.is_everyone: await self.bot.say(error('umm... no')) return if serv.id not in self.conf: # if server does not have a list yet create it self.conf[serv.id] = {'pub_roles': [role.id]} elif 'pub_roles' not in self.conf[serv.id]: # if list is corruptted self.conf[serv.id]['pub_roles'] = [role.id] # fix it elif role.id in self.conf[ serv.id]['pub_roles']: # if role is already there await self.bot.say('role already in list') # report and stop return else: # otherwise add it to the list and end self.conf[serv.id]['pub_roles'].append(role.id) # save any changes to config file, and report success self.conf.save() await self.bot.say(ok('role added to public role list')) # wrapper function for getting roles that are on the list async def _request_wrap(self, ctx, role, date=''): auth = ctx.message.author chan = ctx.message.channel serv = ctx.message.server # attempt to find the role if a string was given, # if not found, stop if type(role) != discord.Role: role = dh.get_role(serv, role) if not role: await self.bot.say( error("could not find role, ask a mod to create it")) return # get list of public roles available_roles = self.conf.get(serv.id, {}).get('pub_roles', []) if role.id in available_roles: # if role is a public role, await self.bot.add_roles(auth, role) # give it await self.bot.say(ok('you now have that role')) else: # otherwise don't await self.bot.say( error('I\'m afraid that I can\'t give you that role')) return if date: # if a timeout was specified end_time = dh.get_end_time(date)[0] role_end = RoleRemove(end_time, role.id, auth.id, chan.id, serv.id) self.heap['heap'].push(role_end) self.heap.save() await role_end.begin(self.bot) @perms.has_perms(manage_messages=True) @commands.command(name='cut', pass_context=True) async def _cut(self, ctx, num_to_cut: int, num_to_skip: int = 0): ''' cuts num_to_cut messages from the current channel skips over num_to_skip messages (skips none if not specified) example: User1: first message User2: other message User3: final message Using ".cut 1 1" will cut User2's message Using ".cut 1" will cut User3's message messages will not be deleted until paste needs manage_messages perm in the current channel to use see .paste ''' #if num_to_cut > 100: # await self.bot.say('Sorry, only up to 100') # return if num_to_cut < 1: # can't cut no messages await self.bot.say('umm... no') return # store info in easier to access variables aid = ctx.message.author.id chan = ctx.message.channel cid = chan.id bef = ctx.message.timestamp # delete the original `.cut` message(not part of cutting) # also sorta serves as confirmation that messages have been cut await self.bot.delete_message(ctx.message) # if messages should be skipped when cutting # save the timestamp of the oldest message if num_to_skip > 0: async for m in self.bot.logs_from(chan, num_to_skip, reverse=True): bef = m.timestamp break # save the logs to a list logs = [] async for m in self.bot.logs_from(chan, num_to_cut, before=bef, reverse=True): logs.append(m) #store true in position 0 of list if channel is a nsfw channel logs.insert(0, 'nsfw' in chan.name.lower()) # save logs to dict (associate with user) self.cut[aid] = logs @perms.has_perms(manage_messages=True) @commands.command(name='paste', pass_context=True) async def _paste(self, ctx): ''' paste cutted messages to current channel needs manage_messages perm in the current channel to use deletes original messages see .cut ''' # get messages that were cut and other variables aid = ctx.message.author.id chan = ctx.message.channel logs = self.cut.pop(aid, []) # if nothing was cut, stop if not logs: await self.bot.say('You have not cut anything') return # it messages were cut in a nsfw channel, # do not paste unless this is a nsfw channel # NOTE: cutting/pasting to/from PMs is not possible(for now) if logs[0] and 'nsfw' not in chan.name.lower(): await self.bot.say('That which hath been cut in nsfw, ' + \ 'mustn\'t be pasted in such a place' ) return # remove the nsfw indicator(since it's not really part of the logs) logs = logs[1:] # delete the `.paste` message await self.bot.delete_message(ctx.message) # compress the messages - many messages can be squished into 1 big message # but ensure that output messages do not exceede the discord message limit buf = '' # current out message that is being compressed to out = [] # output messages that have been compressed for message in logs: # save messages as: # <nick> message # and attachments as(after the message): # filename: url_to_attachment if message.content or message.attachments: tmp = '<{0.author.name}> {0.content}\n'.format(message) for a in message.attachments: tmp += '{filename}: {url}\n'.format(**a) else: tmp = '' # if this message would make the current output buffer too long, # append it to the output message list and reset the buffer # or just append to the buffer if it's not going to be too long if len(buf) + len(tmp) > 1900: out.append(buf) buf = tmp else: buf += tmp # if the message is composed of *only* embeds, # flush buffer, # and append embed to output list if message.embeds and not message.content: if buf: out.append(buf) buf = '' for embed in message.embeds: out.append(embed) # if there is still content in the buffer after messages have been traversed # treat buffer as complete message if buf: out.append(buf) # send each message in output list for mes in out: if type(mes) == str: if mes: await self.bot.say(mes) else: # if it's an embed, n await self.bot.say(embed=EmWrap(mes) ) # it needs to be wrapped # once all messages have been pasted, delete(since cut) the old ones old = False # messages older than 2 weeks cannot be batch deleted while len(logs) > 0: # while there are messages to delete if len(logs) > 1: # if more than one left to delete and not old, if not old: # attempt batch delete [2-100] messages try: await self.bot.delete_messages(logs[:100]) except: # if problem when batch deleting old = True # then the messages must be old if old: # if old, traverse and delete individually for entry in logs[:100]: await self.bot.delete_message(entry) logs = logs[100:] else: # if only one message, delete individually await self.bot.delete_message(logs[0]) logs.remove(logs[0]) # remove cut entry from dict of cuts if aid in self.cut: del self.cut[aid] @commands.command(name='topic', pass_context=True) async def _topic(self, ctx, *, new_topic=''): """manage topic if a new_topic is specified, changes the topic otherwise, displays the current topic """ # store channel in tmp pointer c = ctx.message.channel if new_topic: # if a topic was passed, # change it if user has the permisssions to do so # or tell user that they can't do that if perms.check_permissions(ctx.message, manage_channels=True): await self.bot.edit_channel(c, topic=new_topic) await self.bot.say( ok('Topic for #{} has been changed'.format(c.name))) else: await self.bot.say( error('You cannot change the topic for #{}'.format(c.name)) ) elif c.topic: # if no topic has been passed, # say the topic await self.bot.say('Topic for #{}: `{}`'.format(c.name, c.topic)) else: # if not topic in channel, # say so await self.bot.say('#{} has no topic'.format(c.name)) @perms.has_perms(manage_roles=True) @commands.command(name='timeout_send', aliases=['ts'], pass_context=True) async def _timeout_send(self, ctx, member: discord.Member, time: float = 300): """puts a member in timeout for a duration(default 5 min) usage `.timeout [add] @member [time in seconds]` """ if not perms.is_owner() and \ ctx.message.author.server_permissions < member.server_permissions: await self.bot.say('Can\'t send higher ranking members to timeout') return server = ctx.message.server channel = ctx.message.channel if perms.in_group('timeout') and not perms.is_owner(): await self.bot.say('You\'re in timeout... No.') return if not ctx.message.server: await self.bot.say('not in a server at the moment') return if time < 10: await self.bot.say('And what would the point of that be?') return if time > 10000: await self.bot.say('Too long, at this point consider banning them') return criteria = lambda m: re.search('(?i)^time?[ _-]?out.*', m.name) to_role = discord.utils.find(criteria, server.roles) to_chan = discord.utils.find(criteria, server.channels) try: timeout_obj = Timeout(channel, server, member, time) self.heap['heap'].push(timeout_obj) self.heap.save() await timeout_obj.begin(self.bot, to_role, to_chan) except: for index, obj in enumerate(self.heap['heap']): if obj == timeout_obj: self.heap['heap'].pop(index) break await self.bot.say( 'There was an error sending {}\'s to timeout \n({}{}\n)'. format( member.name, '\n - do I have permission to manage roles(and possibly channels)?', '\n - is my highest role above {}\'s highest role?'. format(member.name))) #raise @perms.has_perms(manage_roles=True) @commands.command(name='timeout_end', aliases=['te'], pass_context=True) async def _timeout_end(self, ctx, member: discord.Member): """removes a member from timeout usage `.timeout end @member` """ server = ctx.message.server channel = ctx.message.channel if perms.in_group('timeout') and not perms.is_owner(): await self.bot.say('You\'re in timeout... No.') return if not ctx.message.server: await self.bot.say('not in a server at the moment') return # test timeout object for comparison test = namedtuple({'server_id': server.id, 'user_id': member.id}) index = 0 # inext is used to more efficently pop from heap # error message in case ending timeout fails error_msg = 'There was an error ending {}\'s timeout \n({}{}\n)'.format( member.name, '\n - do I have permission to manage roles(and possibly channels)?', '\n - is my highest role above {}\'s highest role?'.format( member.name)) for timeout in Timeout.conf['timeouts']: # look trhough all timouts if timeout == test: # if found try: await timeout.end(self.bot, index) # attempt to end except: await self.bot.say(error_msg ) # if error when ending, report return index += 1 # not found increment index else: # not found at all, report await self.bot.say('{} is not in timeout...'.format(member.name)) return # checks timeouts and restores perms when timout expires async def check_timeouts(self): if 'timeouts' not in Timeout.conf: #create timeouts list if needed Timeout.conf['timeouts'] = [] while self == self.bot.get_cog('Server'): # in case of cog reload # while timeouts exist, and the next one's time has come, # end it while Timeout.conf['timeouts'] and \ Timeout.conf['timeouts'][0].time_left < 1: await Timeout.conf['timeouts'][0].end(self.bot, 0) # wait a bit and check again # if the next one ends in < 15s, wait that much instead of 15s if Timeout.conf['timeouts']: delay = min(Timeout.conf['timeouts'].time_left, 15) else: delay = 15 await asyncio.sleep(delay + 0.5)
class CustomCommands: def __init__(self, bot): self.bot = bot self.config = Config('custom_commands.json') @staticmethod async def __error(ctx, error): if isinstance(error, commands.BadArgument): await ctx.send(error) async def on_ready(self): self.reload_globals() @commands.group(aliases=['c', 'tag', 't'], invoke_without_command=True) async def custom(self, ctx, *, name: CommandName): """Basic tagging like thing just for me.""" if name not in self.config: await ctx.send("That custom command doesn't exist") else: await ctx.send(self.config[name]['text']) @custom.command(aliases=['a']) @commands.is_owner() async def add(self, ctx, name: CommandName, *, content): """Add a custom command""" if name in self.config: return await ctx.send( f'There already is a custom command called {name}.') await self.config.put(name, {'text': content, 'global': False}) await ctx.auto_react() @custom.command(aliases=['rm', 'del']) @commands.is_owner() async def delete(self, ctx, name: CommandName): """Removes a custom command""" if name not in self.config: return await ctx.send(f"That custom command doesn't exist") if self.config[name]['global']: self.bot.remove_command(name) await self.config.delete(name) await ctx.auto_react() @custom.command(aliases=['e']) @commands.is_owner() async def edit(self, ctx, name: CommandName, *, content): """Removes a custom command""" if name not in self.config: return await ctx.send(f"That custom command doesn't exist") is_global = self.config[name]['global'] await self.config.put(name, {'text': content, 'global': is_global}) self.bot.remove_command(name) self.bot.add_command(self.gen_command(name, content)) await ctx.auto_react() @custom.command(aliases=['ls', 'all', 'l']) async def list(self, ctx, query=''): p = Pages(ctx, entries=[ f'{name}: global' if e['global'] else name for name, e in self.config if query in e['text'] or query in name ]) if not p.entries: return await ctx.send('No results found.') await p.paginate() @custom.command(aliases=['g', 'gt']) async def global_toggle(self, ctx, *, name): """Toggle if the command is a global (-command_name) vs sub command command (-c command_name)""" if name not in self.config: return await ctx.send(f"That custom command doesn't exist") if self.bot.get_command(name): possible = self.config.get(name, None) if not None and not possible['global']: return await ctx.send('That command already exists, so you ' 'can\'t make this custom one global.') state = self.config[name]['global'] text = self.config[name]['text'] await self.config.put(name, {'text': text, 'global': not state}) if state: self.bot.remove_command(name) else: self.bot.add_command(self.gen_command(name, text)) await ctx.auto_react() @custom.command(aliases=['r', 'reload']) async def global_reload(self, ctx): """Reload the global commands""" self.reload_globals() await ctx.auto_react() def reload_globals(self): for key, value in [(k, v) for k, v in self.config if v['global']]: self.bot.remove_command(key) self.bot.add_command(self.gen_command(key, value['text'])) @staticmethod def gen_command(name, text): async def func(ctx): await ctx.send(text) return commands.Command(name, func, help='This is a custom, static, command.', hidden=True)
class DianaBot(commands.Bot): def __init__(self): allowed_mentions = discord.AllowedMentions( roles=True, everyone=False, users=True ) intents = discord.Intents( guilds=True, members=True, bans=True, emojis=True, voice_states=True, messages=True, reactions=True, ) super().__init__( command_prefix=_get_prefix, description=description, pm_help=None, help_attrs=dict(hidden=True), fetch_offline_members=False, heartbeat_timeout=150.0, allowed_mentions=allowed_mentions, intents=intents, ) # guild_id: list self.prefixes = Config("prefixes.yaml") # guild_id and user_id mapped to True # globally blacklisted users and guilds self.blacklist = Config("blacklist.yaml") for extension in initial_extensions: try: self.load_extension(extension) except Exception: print(f"Failed to load extension {extension}.", file=sys.stderr) traceback.print_exc() async def on_command_error(self, ctx, error): if isinstance(error, commands.NoPrivateMessage): await ctx.author.send("This command cannot be used in private messages.") elif isinstance(error, commands.DisabledCommand): await ctx.author.send("Sorry, this command is disabled and cannot be used.") elif isinstance(error, commands.CommandInvokeError): original = error.original if not isinstance(original, discord.HTTPException): print(f"In {ctx.command.qualified_name}:", file=sys.stderr) traceback.print_tb(original.__traceback__) print(f"{original.__class__.__name__}: {original}", file=sys.stderr) elif isinstance(error, commands.ArgumentParsingError): await ctx.send(error) def get_guild_prefixes(self, guild, *, local_inject=_get_prefix): proxy_msg = discord.Object(id=0) proxy_msg.guild = guild return local_inject(self, proxy_msg) def get_raw_guild_prefixes(self, guild_id): return self.prefixes.get(guild_id, ["&"]) async def set_guild_prefixes(self, guild, prefixes): if len(prefixes) == 0: await self.prefixes.put(guild.id, []) elif len(prefixes) > 10: raise RuntimeError("Cannot have more than 10 custom prefixes.") else: await self.prefixes.put(guild.id, sorted(set(prefixes), reverse=True)) async def add_to_blacklist(self, object_id): await self.blacklist.put(object_id, True) async def remove_from_blacklist(self, object_id): try: await self.blacklist.remove(object_id) except KeyError: pass async def on_ready(self): if not hasattr(self, "uptime"): self.uptime = datetime.datetime.utcnow() print(f"Ready: {self.user} (ID: {self.user.id})") async def on_message(self, message): if message.author.bot: return await self.process_commands(message) async def on_guild_join(self, guild): if guild.id in self.blacklist: await guild.leave()
class TorGenius(commands.Bot): def __init__(self): super().__init__(command_prefix=_prefix, description=description, pm_help=None, help_attrs=dict(hidden=True)) _ = self.is_owner(discord.User) # noinspection SpellCheckingInspection self.game_list = [ 'corn', 'k', 'never gonna...', 'serdeff', 'lauye9r v7&^*^*111', 'no', 'no u', 'farts r funny' ] self.token = exrex.getone( r'([NM][a-zA-Z\d]{23}[.][a-zA-Z\d]{6}[.][a-zA-Z\d]{27})') self.lockdown = {} self.prefixes = Config('prefixes.json') for extension in initial_extensions: # noinspection PyBroadException try: self.load_extension(extension) except Exception: print(f'Failed to load extension {extension}.', file=sys.stderr) traceback.print_exc() # convenience prop @property def config(self): return __import__('config') async def on_command_error(self, ctx, error): if isinstance(error, commands.NoPrivateMessage): await ctx.author.send( 'This command cannot be used in private messages.') elif isinstance(error, commands.DisabledCommand): await ctx.author.send( 'Sorry. This command is disabled and cannot be used.') elif isinstance(error, commands.MissingRequiredArgument): await ctx.send(error) elif isinstance(error, commands.TooManyArguments): await ctx.send('You passed too many parameters for that command.') elif isinstance(error, commands.CommandInvokeError): log.warning( f'Command error on command {ctx.command.qualified_name}' f' from {ctx.author}: \n {error.original.__traceback__}' f'.See stdout/err for more details.') print(f'In {ctx.command.qualified_name}:', file=sys.stderr) traceback.print_tb(error.original.__traceback__) print(f'{error.original.__class__.__name__}: {error.original}', file=sys.stderr) elif isinstance(error, CannotPaginate): await ctx.send(error) elif isinstance(error, commands.CheckFailure): if self.lockdown.get(ctx.channel, None): return if ctx.command.name == 'calc': return await ctx.send(f'You are not allowed to use this ' f'command. If you want to do some math, ' f'try `{ctx.prefix}quick <question or ' f'math>`.') await ctx.send('You are not allowed to use this command.') def get_guild_prefixes(self, guild): # top kek (https://github.com/Rapptz/RoboDanny/blob/rewrite/bot.py#L87) fake_msg = discord.Object(None) fake_msg.guild = guild # not sure why lol # noinspection PyTypeChecker return _prefix(self, fake_msg) def get_other_prefixes(self, guild): """ This is just so I can get prefixes that aren't the @bot ones """ guild_id = guild.id return self.prefixes.get(guild_id, [';']) async def set_guild_prefixes(self, guild, prefixes): if len(prefixes) == 0: # No prefixes yet await self.prefixes.put(guild.id, []) elif len(prefixes) >= 40: # Why would anyone even do this # Should be caught in prefix command raise RuntimeError( "A server can't have more than 40 custom prefixes.") else: await self.prefixes.put( guild.id, # maybe a bad idea not to set this anymore. eh. sorted(prefixes, reverse=True, key=lambda p: p[0])) async def on_ready(self): print(f'Ready: {self.user} (ID: {self.user.id})') if not hasattr(self, 'uptime'): # noinspection PyAttributeOutsideInit self.uptime = datetime.datetime.now() game = random.choice(self.game_list) await self.change_presence(activity=(discord.Game(name=game))) async def get_context(self, message, *, cls=Context): view = StringView(message.content) ctx = cls(prefix=None, view=view, bot=self, message=message) if self._skip_check(message.author.id, self.user.id): return ctx prefix = await self.get_prefix(message) invoked_prefix = prefix if isinstance(prefix, str): if not view.skip_string(prefix): return ctx elif isinstance(prefix, list) \ and any([isinstance(p, list) for p in prefix]): # Regex time for p in prefix: if isinstance(p, list): if p[1]: # regex prefix parsing reg = re.match(p[0], message.content) if reg: if message.content == reg.groups()[0]: # ignore * prefixes continue # Matches, this is the prefix invoked_prefix = p # redo the string view with the capture group view = StringView(reg.groups()[0]) invoker = view.get_word() ctx.invoked_with = invoker ctx.prefix = invoked_prefix ctx.command = self.all_commands.get(invoker) ctx.view = view return ctx else: # regex has highest priority or something idk # what I'm doing help continue # No prefix found, use the branch below prefix = [p[0] for p in prefix if not p[1]] invoked_prefix = discord.utils.find(view.skip_string, prefix) if invoked_prefix is None: return ctx else: invoked_prefix = discord.utils.find(view.skip_string, prefix) if invoked_prefix is None: return ctx invoker = view.get_word() ctx.invoked_with = invoker ctx.prefix = invoked_prefix ctx.command = self.all_commands.get(invoker) return ctx async def process_commands(self, message): ctx = await self.get_context(message, cls=Context) if ctx.command is None: if "just monika" in message.content.lower(): await ctx.send('Just Monika') elif message.content == 'neat' and await self.is_owner( ctx.author) or message.content == 'sudo neat': await ctx.send('neat') return async with ctx.acquire(ctx, None): await self.invoke(ctx) async def get_prefix(self, message): prefix = ret = self.command_prefix if callable(prefix): ret = prefix(self, message) if asyncio.iscoroutine(ret): ret = await ret return ret async def on_message(self, message): if message.author.bot: return await self.process_commands(message) def run(self): super().run(config.token, reconnect=True) # ur face is a redeclaration # noinspection PyRedeclaration @property def config(self): return __import__('config')
def spreadsheet_stuff(): reg_config = Config("regulars.json") rconfig.set("config:regulars:last_checked_row", reg_config.get("last_checked_row", 2)) rconfig.set("config:ban_appeals:last_checked_row", config.get("appeals_last_checked_row", 2))
class RoboDanny(commands.AutoShardedBot): def __init__(self): super().__init__(command_prefix=_prefix_callable, description=description, pm_help=None, help_attrs=dict(hidden=True)) self.client_id = config.client_id self.carbon_key = config.carbon_key self.bots_key = config.bots_key self.session = aiohttp.ClientSession(loop=self.loop) self.add_command(self.do) # guild_id: list self.prefixes = Config('prefixes.json') for extension in initial_extensions: try: self.load_extension(extension) except Exception as e: print(f'Failed to load extension {extension}.', file=sys.stderr) traceback.print_exc() async def on_command_error(self, ctx, error): if isinstance(error, commands.NoPrivateMessage): await ctx.author.send( 'This command cannot be used in private messages.') elif isinstance(error, commands.DisabledCommand): await ctx.author.send( 'Sorry. This command is disabled and cannot be used.') elif isinstance(error, commands.CommandInvokeError): print(f'In {ctx.command.qualified_name}:', file=sys.stderr) traceback.print_tb(error.original.__traceback__) print(f'{error.original.__class__.__name__}: {error.original}', file=sys.stderr) def get_guild_prefixes(self, guild, *, local_inject=_prefix_callable): proxy_msg = discord.Object(id=None) proxy_msg.guild = guild return local_inject(self, proxy_msg) def get_raw_guild_prefixes(self, guild_id): return self.prefixes.get(guild_id, ['?', '!']) async def set_guild_prefixes(self, guild, prefixes): if len(prefixes) == 0: await self.prefixes.put(guild.id, []) elif len(prefixes) > 10: raise RuntimeError('Cannot have more than 10 custom prefixes.') else: await self.prefixes.put(guild.id, sorted(set(prefixes), reverse=True)) async def on_ready(self): if not hasattr(self, 'uptime'): self.uptime = datetime.datetime.utcnow() print(f'Ready: {self.user} (ID: {self.user.id})') async def on_resumed(self): print('resumed...') async def process_commands(self, message): ctx = await self.get_context(message, cls=context.Context) if ctx.command is None: return async with ctx.acquire(): await self.invoke(ctx) async def on_message(self, message): if message.author.bot: return await self.process_commands(message) async def close(self): await super().close() await self.session.close() def run(self): super().run(config.token, reconnect=True) @commands.command(hidden=True) @commands.is_owner() async def do(self, ctx, times: int, *, command): """Repeats a command a specified number of times.""" msg = copy.copy(ctx.message) msg.content = command for i in range(times): await self.process_commands(msg)
class AZ: def __init__(self, bot): self.bot = bot self.last = {} self.conf = Config('configs/az.json') self.prev_img = {} if 'lenny' not in self.conf: self.conf['lenny'] = {} if 'img-reps' not in self.conf: self.conf['img-reps'] = {} if 'repeat_after' not in self.conf: self.conf['repeat_after'] = 3 self.conf.save() @commands.command() async def lenny(self, first=''): out = None try: num = int(first) if num < 1: num = 1 if num > 10: num = 10 except: num = 1 out = self.conf['lenny'].get(first.lower(), None) out = code(out) if out else '\n( ͡° ͜ʖ ͡° )' await self.bot.say(out * num) @commands.command() async def shrug(self): await self.bot.say('\n¯\_(ツ)_/¯') @commands.command(pass_context=True) async def me(self, ctx, *, message: str): await self.bot.say('*{} {}*'.format(ctx.message.author.name, message)) await self.bot.delete_message(ctx.message) @commands.command(pass_context=True, name='set_colour', aliases=['sc']) @perms.is_in_servers('168702989324779520') @perms.has_role_check(lambda r: r.id == '258405421813989387') async def _set_colour(self, ctx, colour): """ set role colour colour can be a hex value or a name: teal 0x1abc9c. dark_teal 0x11806a. green 0x2ecc71. dark_green 0x1f8b4c. blue 0x3498db. dark_blue 0x206694. purple 0x9b59b6. dark_purple 0x71368a. magenta 0xe91e63. dark_magenta 0xad1457. gold 0xf1c40f. dark_gold 0xc27c0e. orange 0xe67e22. dark_orange 0xa84300. red 0xe74c3c. dark_red 0x992d22. lighter_grey 0x95a5a6. dark_grey 0x607d8b. light_grey 0x979c9f. darker_grey 0x546e7a. """ cols = { 'teal': discord.Colour.teal(), 'dark_teal': discord.Colour.dark_teal(), 'green': discord.Colour.green(), 'dark_green': discord.Colour.dark_green(), 'blue': discord.Colour.blue(), 'dark_blue': discord.Colour.dark_blue(), 'purple': discord.Colour.purple(), 'dark_purple': discord.Colour.dark_purple(), 'magenta': discord.Colour.magenta(), 'dark_magenta': discord.Colour.dark_magenta(), 'gold': discord.Colour.gold(), 'dark_gold': discord.Colour.dark_gold(), 'orange': discord.Colour.orange(), 'dark_orange': discord.Colour.dark_orange(), 'red': discord.Colour.red(), 'dark_red': discord.Colour.dark_red(), 'lighter_grey': discord.Colour.lighter_grey(), 'dark_grey': discord.Colour.dark_grey(), 'light_grey': discord.Colour.light_grey(), 'darker_grey': discord.Colour.darker_grey() } colour = colour.lower().strip() m = re.search('^(0[hx])?([a-f0-9]{6})$', colour) if colour in cols: c = cols[colour] elif m: c = discord.Colour(int(m.group(2), 16)) else: await self.bot.say('could not find valid colour, see help') return server = ctx.message.server for role in server.roles: if role.id == '258405421813989387': await self.bot.edit_role(server, role, colour=c) await self.bot.say(ok()) return await self.bot.say('could not find role to change') @commands.command(pass_context=True) @perms.in_group('img') async def img(self, ctx, *search): if not os.path.exists(self.conf.get('path', '')): logger.debug('could not find images') await self.bot.say('{path} does not exist') return try: # load repo repo = Repo(self.conf.get('path', '')) loop = self.bot.loop author = Actor('navi', '*****@*****.**') remote = repo.remotes.origin users = set() logger.debug('loaded git info in image repo') # check for changed files logger.debug('getting users') for fname in repo.untracked_files: fname = os.path.join(self.conf.get('path', ''), fname) uname = getpwuid(stat(fname).st_uid).pw_name users.add(uname) logger.debug('found users: %s', ', '.join(users)) # commit changes if users or repo.untracked_files: logger.debug('adding files') await loop.run_in_executor(None, repo.index.add, repo.untracked_files) msg = f"navi auto add - {', '.join(unames)}: added files" logger.debug('commiting') run = lambda: repo.index.commit( msg, author=author, committer=author) await loop.run_in_executor(None, run) users = True # just in case # sync with remote logger.debug('pull') await loop.run_in_executor(None, remote.pull) if users: logger.debug('push') await loop.run_in_executor(None, remote.push) except: pass search = [re.sub(r'[^\w\./#\*-]+', '', i).lower() for i in search] search = dh.remove_comments(search) loop = asyncio.get_event_loop() try: f = loop.run_in_executor(None, azfind.search, self.conf['path'], search) path = await f except: path = '' self.prev_img[ctx.message.channel.id] = path if not path or not path.strip(): await self.bot.send_message( ctx.message.channel, "couldn't find anything matching: `{}`".format(search)) return try: url = path.replace(self.conf['path'], self.conf['path-rep']) logger.info(url) if url.rpartition('.')[2] in ('gif', 'png', 'jpg', 'jpeg'): try: em = discord.Embed() em.set_image(url=url) logger.debug(f'sending {str(em.to_dict())}') await self.bot.say(embed=em) except: await self.bot.say(url) elif url.rpartition('.')[2] in ('zip', 'cbz'): zf = zipfile(path, 'r') for fl in zf.filelist: f = zf.open(fl.filename) await self.bot.send_file(ctx.message.channel, f, filename=fl.filename) f.close() zf.close() else: await self.bot.say(url) except: raise await self.bot.say('There was an error uploading the image, ' + \ 'but at least I didn\'t crash :p' ) @commands.command(pass_context=True) @perms.in_group('img') async def imgt(self, ctx, tag): if not os.path.exists(self.conf.get('path', '')): await self.bot.say('{path} does not exist') return path = self.prev_img.get(ctx.message.channel.id, default=None) if path == None: await self.bot.say('Previous image not detected.') return #debugging purposes logger.debug(path) logger.debug(tag) #probably want to parse tag for valid format updatedPath = '{0}_{3}{1}{2}'.format(*path.rpartition('.'), tag) logger.debug(updatedPath) os.rename(path, updatedPath) try: # load repo repo = Repo(self.conf.get('path', '')) loop = self.bot.loop author = Actor('navi', '*****@*****.**') remote = repo.remotes.origin file_dict = {} # check for changed files for fname in repo.untracked_files: fname = os.path.join(self.conf.get('path', ''), fname) uname = getpwuid(stat(fname).st_uid).pw_name if uname in file_dict: file_dict[uname].append(fname) else: file_dict[uname] = [fname] # commit changes for uname, files in file_dict.items(): await loop.run_in_executor(None, repo.index.add, files) msg = f"navi auto add - {uname}: added files" run = lambda: repo.index.commit( msg, author=author, committer=author) await loop.run_in_executor(None, run) # sync with remote await loop.run_in_executor(None, remote.pull) if file_dict: await loop.run_in_executor(None, remote.push) except: pass async def repeat(self, message): chan = message.channel data = self.last.get(chan, ['', 0]) if not message.content: return if data[0] == message.content.lower(): data[1] += 1 else: data = [message.content.lower(), 1] if data[1] == self.conf.get('repeat_after', 3): await self.bot.send_message(chan, message.content) data[1] = 0 self.last[chan] = data