diff --git a/.gitignore b/.gitignore
index a68779da8b3eb7877b954989d98fb168649f0815..6041bfc1eb7aab1ee2992dfe534be344978498e3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,18 +1,7 @@
 # Caches
 __pycache__/*
 */__pycache__
-Plex-bot/cogs/__pycache__
-Develoment-bot/cogs/__pycache__
-
-# Temp files
-.invisible
 
 # Idea files
 .idea/*
 
-# Plex bot related files
-Plex-bot/config.ini
-Plex-bot/*/test.py
-
-# Develoment bot related
-Develoment-bot/config.ini
diff --git a/Music-bot/bot.py b/Music-bot/bot.py
index f1431d1ff35a1c61c29d3056b3f39b2c11744d07..8ee3768f126e1a29b2f7271502fa6077998abb00 100644
--- a/Music-bot/bot.py
+++ b/Music-bot/bot.py
@@ -20,7 +20,7 @@ bot = commands.Bot(command_prefix=get_prefix, help_attrs=help_attrs, description
 @bot.event
 async def on_ready():
     bot.uptime = datetime.datetime.utcnow()
-    print('Logged in as:\n{0} (ID: {0.id})'.format(bot.user))
+    print(f'\n\nLogged in as: {bot.user.name} - {bot.user.id}\nAPI Version: {discord.__version__}\n')
 
 
 @bot.event
diff --git a/Music-bot/cogs/error_handler.py b/Music-bot/cogs/error_handler.py
index 154e81f9bba24c2f6ae7e80aef3d178e7ad223c8..0b33bc15e17a4b7e6a88aad00fecdbc450632393 100644
--- a/Music-bot/cogs/error_handler.py
+++ b/Music-bot/cogs/error_handler.py
@@ -8,7 +8,7 @@ class CommandErrorHandler:
 	def __init__(self, bot):
 		self.bot = bot
 
-	async def on_command_error(self, error, ctx):
+	async def on_command_error(self, ctx, error):
 		"""The event triggered when an error is raised while invoking a command.
 		ctx   : Context
 		error : Exception"""
diff --git a/Music-bot/cogs/meta.py b/Music-bot/cogs/meta.py
index e6c70495312eb4b3e711180ae1d578d6a736380e..e44c297a07425c5fdc10aaa54976b582c4e71002 100644
--- a/Music-bot/cogs/meta.py
+++ b/Music-bot/cogs/meta.py
@@ -1,33 +1,9 @@
 import discord
 import datetime
 from discord.ext import commands
-from .utils import checks, formats
 from collections import Counter
 
 
-class TimeParser:
-	def __init__(self, argument):
-		compiled = re.compile(r"(?:(?P<hours>\d+)h)?(?:(?P<minutes>\d+)m)?(?:(?P<seconds>\d+)s)?")
-		self.original = argument
-		try:
-			self.seconds = int(argument)
-		except ValueError as e:
-			match = compiled.match(argument)
-			if match is None or not match.group(0):
-				raise commands.BadArgument('Failed to parse time.') from e
-
-			self.seconds = 0
-			hours = match.group('hours')
-			if hours is not None:
-				self.seconds += int(hours) * 3600
-			minutes = match.group('minutes')
-			if minutes is not None:
-				self.seconds += int(minutes) * 60
-			seconds = match.group('seconds')
-			if seconds is not None:
-				self.seconds += int(seconds)
-
-
 class Meta:
 	"""Commands for utilities related to Discord or the Bot itself."""
 
@@ -52,7 +28,7 @@ class Meta:
 		await self.bot.say('Uptime: **{}**'.format(self.get_bot_uptime()))
 
 	@commands.command(name='quit', hidden=True)
-	@checks.is_owner()
+	@commands.is_owner()
 	async def _quit(self):
 		"""Quits the bot."""
 		await self.bot.logout()
diff --git a/Music-bot/cogs/misc.py b/Music-bot/cogs/misc.py
index d5173d8b41931d6208a26bd479754a6bf6628c55..0f806191ce76d783a1bd3e2decc1a366c2a1d6ff 100644
--- a/Music-bot/cogs/misc.py
+++ b/Music-bot/cogs/misc.py
@@ -17,4 +17,4 @@ class Misc:
 
 
 def setup(bot):
-	bot.add_cog(Misc(bot))
\ No newline at end of file
+	bot.add_cog(Misc(bot))
diff --git a/Music-bot/cogs/mod.py b/Music-bot/cogs/mod.py
deleted file mode 100644
index 3567300ab43f2ae779667d75b8fb8e07cee600e6..0000000000000000000000000000000000000000
--- a/Music-bot/cogs/mod.py
+++ /dev/null
@@ -1,313 +0,0 @@
-# Borrowed from https://github.com/Rapptz/RoboDanny/tree/async
-
-from discord.ext import commands
-from .utils import config, checks
-from collections import Counter
-import discord
-
-
-class Mod:
-	"""Moderation related commands."""
-
-	def __init__(self, bot):
-		self.bot = bot
-		self.config = config.Config('mod.json', loop=bot.loop)
-
-	def bot_user(self, message):
-		return message.server.me if message.channel.is_private else self.bot.user
-
-	@commands.group(pass_context=True, no_pm=True)
-	@checks.admin_or_permissions(manage_channel=True)
-	async def ignore(self, ctx):
-		"""Handles the bot's ignore lists.
-		To use these commands, you must have the Bot Admin role or have
-		Manage Channel permissions. These commands are not allowed to be used
-		in a private message context.
-		Users with Manage Roles or Bot Admin role can still invoke the bot
-		in ignored channels.
-		"""
-		if ctx.invoked_subcommand is None:
-			await self.bot.say('Invalid subcommand passed: {0.subcommand_passed}'.format(ctx))
-
-	@ignore.command(name='channel', pass_context=True)
-	async def channel_cmd(self, ctx, *, channel: discord.Channel = None):
-		"""Ignores a specific channel from being processed.
-		If no channel is specified, the current channel is ignored.
-		If a channel is ignored then the bot does not process commands in that
-		channel until it is unignored.
-		"""
-
-		if channel is None:
-			channel = ctx.message.channel
-
-		ignored = self.config.get('ignored', [])
-		if channel.id in ignored:
-			await self.bot.say('That channel is already ignored.')
-			return
-
-		ignored.append(channel.id)
-		await self.config.put('ignored', ignored)
-		await self.bot.say('\U0001f44c')
-
-	@ignore.command(name='all', pass_context=True)
-	@checks.admin_or_permissions(manage_server=True)
-	async def _all(self, ctx):
-		"""Ignores every channel in the server from being processed.
-		This works by adding every channel that the server currently has into
-		the ignore list. If more channels are added then they will have to be
-		ignored by using the ignore command.
-		To use this command you must have Manage Server permissions along with
-		Manage Channel permissions. You could also have the Bot Admin role.
-		"""
-
-		ignored = self.config.get('ignored', [])
-		channels = ctx.message.server.channels
-		ignored.extend(c.id for c in channels if c.type == discord.ChannelType.text)
-		await self.config.put('ignored', list(set(ignored)))  # make unique
-		await self.bot.say('\U0001f44c')
-
-	@commands.command(pass_context=True, no_pm=True)
-	@checks.admin_or_permissions(manage_channel=True)
-	async def unignore(self, ctx, *, channel: discord.Channel = None):
-		"""Unignores a specific channel from being processed.
-		If no channel is specified, it unignores the current channel.
-		To use this command you must have the Manage Channel permission or have the
-		Bot Admin role.
-		"""
-
-		if channel is None:
-			channel = ctx.message.channel
-
-		# a set is the proper data type for the ignore list
-		# however, JSON only supports arrays and objects not sets.
-		ignored = self.config.get('ignored', [])
-		try:
-			ignored.remove(channel.id)
-		except ValueError:
-			await self.bot.say('Channel was not ignored in the first place.')
-		else:
-			await self.bot.say('\U0001f44c')
-
-	@commands.command(pass_context=True, no_pm=True)
-	@checks.mod_or_permissions(manage_messages=True)
-	async def cleanup(self, ctx, search: int = 100):
-		"""Cleans up the bot's messages from the channel.
-		If a search number is specified, it searches that many messages to delete.
-		If the bot has Manage Messages permissions, then it will try to delete
-		messages that look like they invoked the bot as well.
-		After the cleanup is completed, the bot will send you a message with
-		which people got their messages deleted and their count. This is useful
-		to see which users are spammers.
-		To use this command you must have Manage Messages permission or have the
-		Bot Mod role.
-		"""
-
-		spammers = Counter()
-		channel = ctx.message.channel
-		prefixes = self.bot.command_prefix
-
-		def is_possible_command_invoke(entry):
-			valid_call = any(entry.content.startswith(prefix) for prefix in prefixes)
-			return valid_call and not entry.content[1:2].isspace()
-
-		async for entry in self.bot.logs_from(channel, limit=search):
-			if entry.author == self.bot.user:
-				await self.bot.delete_message(entry)
-				spammers['Bot'] += 1
-			if is_possible_command_invoke(entry):
-				try:
-					await self.bot.delete_message(entry)
-				except discord.Forbidden:
-					continue
-				else:
-					spammers[entry.author.name] += 1
-
-		await self.bot.say('Clean up completed. {} message(s) were deleted.'.format(sum(spammers.values())))
-
-		spammers = sorted(spammers.items(), key=lambda t: t[1], reverse=True)
-		stats = '\n'.join(map(lambda t: '- **{0[0]}**: {0[1]}'.format(t), spammers))
-		await self.bot.whisper(stats)
-
-	@commands.command(no_pm=True)
-	@checks.admin_or_permissions(kick_members=True)
-	async def kick(self, *, member: discord.Member):
-		"""Kicks a member from the server.
-		In order for this to work, the bot must have Kick Member permissions.
-		To use this command you must have Kick Members permission or have the
-		Bot Admin role.
-		"""
-
-		try:
-			await self.bot.kick(member)
-		except discord.Forbidden:
-			await self.bot.say('The bot does not have permissions to kick members.')
-		except discord.HTTPException:
-			await self.bot.say('Kicking failed.')
-		else:
-			await self.bot.say('\U0001f44c')
-
-	@commands.command(no_pm=True)
-	@checks.admin_or_permissions(ban_members=True)
-	async def ban(self, *, member: discord.Member):
-		"""Bans a member from the server.
-		In order for this to work, the bot must have Ban Member permissions.
-		To use this command you must have Ban Members permission or have the
-		Bot Admin role.
-		"""
-
-		try:
-			await self.bot.ban(member)
-		except discord.Forbidden:
-			await self.bot.say('The bot does not have permissions to ban members.')
-		except discord.HTTPException:
-			await self.bot.say('Banning failed.')
-		else:
-			await self.bot.say('\U0001f44c')
-
-	@commands.command(no_pm=True)
-	@checks.admin_or_permissions(ban_members=True)
-	async def softban(self, *, member: discord.Member):
-		"""Soft bans a member from the server.
-		A softban is basically banning the member from the server but
-		then unbanning the member as well. This allows you to essentially
-		kick the member while removing their messages.
-		To use this command you must have Ban Members permissions or have
-		the Bot Admin role. Note that the bot must have the permission as well.
-		"""
-
-		try:
-			await self.bot.ban(member)
-			await self.bot.unban(member.server, member)
-		except discord.Forbidden:
-			await self.bot.say('The bot does not have permissions to ban members.')
-		except discord.HTTPException:
-			await self.bot.say('Banning failed.')
-		else:
-			await self.bot.say('\U0001f44c')
-
-	@commands.command(no_pm=True)
-	@checks.admin_or_permissions(manage_server=True)
-	async def plonk(self, *, member: discord.Member):
-		"""Bans a user from using the bot.
-		Note that this ban is **global**. So they are banned from
-		all servers that they access the bot with. So use this with
-		caution.
-		There is no way to bypass a plonk regardless of role or permissions.
-		The only person who cannot be plonked is the bot creator. So this
-		must be used with caution.
-		To use this command you must have the Manage Server permission
-		or have a Bot Admin role.
-		"""
-
-		plonks = self.config.get('plonks', [])
-		if member.id in plonks:
-			await self.bot.say('That user is already bot banned.')
-			return
-
-		plonks.append(member.id)
-		await self.config.put('plonks', plonks)
-		await self.bot.say('{0.name} has been banned from using the bot.'.format(member))
-
-	@commands.command(no_pm=True)
-	@checks.admin_or_permissions(manage_server=True)
-	async def unplonk(self, *, member: discord.Member):
-		"""Unbans a user from using the bot.
-		To use this command you must have the Manage Server permission
-		or have a Bot Admin role.
-		"""
-
-		plonks = self.config.get('plonks', [])
-
-		try:
-			plonks.remove(member.id)
-		except ValueError:
-			pass
-		else:
-			await self.config.put('plonks', plonks)
-			await self.bot.say('{0.name} has been unbanned from using the bot.'.format(member))
-
-	@commands.command(pass_context=True, no_pm=True)
-	@checks.admin_or_permissions(manage_roles=True)
-	async def colour(self, ctx, colour: discord.Colour, *, role: discord.Role):
-		"""Changes the colour of a role.
-		To use this command you must have the Manage Roles permission or
-		have the Bot Admin role. The bot must also have Manage Roles permissions.
-		This command cannot be used in a private message.
-		"""
-		try:
-			await self.bot.edit_role(ctx.message.server, role, colour=colour)
-		except discord.Forbidden:
-			await self.bot.say('The bot must have Manage Roles permissions to use this.')
-		else:
-			await self.bot.say('\U0001f44c')
-
-	@commands.group(pass_context=True, no_pm=True)
-	@checks.admin_or_permissions(manage_messages=True)
-	async def remove(self, ctx):
-		"""Removes messages that meet a criteria.
-		In order to use this command, you must have Manage Messages permissions
-		or have the Bot Admin role. Note that the bot needs Manage Messages as
-		well. These commands cannot be used in a private message.
-		When the command is done doing its work, you will get a private message
-		detailing which users got removed and how many messages got removed.
-		"""
-
-		if ctx.invoked_subcommand is None:
-			await self.bot.say('Invalid criteria passed "{0.subcommand_passed}"'.format(ctx))
-
-	async def do_removal(self, channel, limit, predicate):
-		spammers = Counter()
-		async for message in self.bot.logs_from(channel, limit=limit):
-			if predicate(message):
-				try:
-					await self.bot.delete_message(message)
-				except discord.Forbidden:
-					await self.bot.say('The bot does not have permissions to delete messages.')
-					return
-				else:
-					spammers[message.author.name] += 1
-
-		await self.bot.say('{} messages(s) were removed.'.format(sum(spammers.values())))
-		spammers = sorted(spammers.items(), key=lambda t: t[1], reverse=True)
-		stats = '\n'.join(map(lambda t: '**{0[0]}**: {0[1]}'.format(t), spammers))
-		await self.bot.whisper(stats)
-
-	@remove.command(pass_context=True)
-	async def embeds(self, ctx, search=100):
-		"""Removes messages that have embeds in them."""
-		await self.do_removal(ctx.message.channel, search, lambda e: len(e.embeds))
-
-	@remove.command(pass_context=True)
-	async def files(self, ctx, search=100):
-		"""Removes messages that have attachments in them."""
-		await self.do_removal(ctx.message.channel, search, lambda e: len(e.attachments))
-
-	@remove.command(pass_context=True)
-	async def images(self, ctx, search=100):
-		"""Removes messages that have embeds or attachments."""
-		await self.do_removal(ctx.message.channel, search, lambda e: len(e.embeds) or len(e.attachments))
-
-	@remove.command(name='all', pass_context=True)
-	async def _remove_all(self, ctx, search=100):
-		"""Removes all messages."""
-		await self.do_removal(ctx.message.channel, search, lambda e: True)
-
-	@remove.command(pass_context=True)
-	async def user(self, ctx, member: discord.Member, search=100):
-		"""Removes all messages by the member."""
-		await self.do_removal(ctx.message.channel, search, lambda e: e.author == member)
-
-	@remove.command(pass_context=True)
-	async def contains(self, ctx, *, substr: str):
-		"""Removes all messages containing a substring.
-		The substring must be at least 3 characters long.
-		"""
-		if len(substr) < 3:
-			await self.bot.say('The substring length must be at least 3 characters.')
-			return
-
-		await self.do_removal(ctx.message.channel, 100, lambda e: substr in e.content)
-
-
-def setup(bot):
-	bot.add_cog(Mod(bot))
diff --git a/Music-bot/cogs/owner.py b/Music-bot/cogs/owner.py
new file mode 100644
index 0000000000000000000000000000000000000000..feee084ba93fb6648fd2566cbd2297a476dabf42
--- /dev/null
+++ b/Music-bot/cogs/owner.py
@@ -0,0 +1,52 @@
+from discord.ext import commands
+
+
+class OwnerCog:
+
+	def __init__(self, bot):
+		self.bot = bot
+
+	# Hidden means it won't show up on the default help.
+	@commands.command(name='load', hidden=True)
+	@commands.is_owner()
+	async def cog_load(self, ctx, *, cog: str):
+		"""Command which Loads a Module.
+		Remember to use dot path. e.g: cogs.owner"""
+
+		try:
+			self.bot.load_extension(cog)
+		except Exception as e:
+			await ctx.send(f'**`ERROR:`** {type(e).__name__} - {e}')
+		else:
+			await ctx.send('**`SUCCESS`**')
+
+	@commands.command(name='unload', hidden=True)
+	@commands.is_owner()
+	async def cog_unload(self, ctx, *, cog: str):
+		"""Command which Unloads a Module.
+		Remember to use dot path. e.g: cogs.owner"""
+
+		try:
+			self.bot.unload_extension(cog)
+		except Exception as e:
+			await ctx.send(f'**`ERROR:`** {type(e).__name__} - {e}')
+		else:
+			await ctx.send('**`SUCCESS`**')
+
+	@commands.command(name='reload', hidden=True)
+	@commands.is_owner()
+	async def cog_reload(self, ctx, *, cog: str):
+		"""Command which Reloads a Module.
+		Remember to use dot path. e.g: cogs.owner"""
+
+		try:
+			self.bot.unload_extension(cog)
+			self.bot.load_extension(cog)
+		except Exception as e:
+			await ctx.send(f'**`ERROR:`** {type(e).__name__} - {e}')
+		else:
+			await ctx.send('**`SUCCESS`**')
+
+
+def setup(bot):
+	bot.add_cog(OwnerCog(bot))
\ No newline at end of file
diff --git a/Music-bot/cogs/utils/checks.py b/Music-bot/cogs/utils/checks.py
deleted file mode 100644
index 9be203cd746bbf76bbabc7a2c6c275a2ef3450c4..0000000000000000000000000000000000000000
--- a/Music-bot/cogs/utils/checks.py
+++ /dev/null
@@ -1,50 +0,0 @@
-# Borrowed from https://github.com/Rapptz/RoboDanny/tree/async
-
-from discord.ext import commands
-import discord.utils
-
-
-def is_owner_check(message):
-	return message.author.id == '157970669261422592'
-
-
-def is_owner():
-	return commands.check(lambda ctx: is_owner_check(ctx.message))
-
-
-def check_permissions(ctx, perms):
-	msg = ctx.message
-	if is_owner_check(msg):
-		return True
-
-	ch = msg.channel
-	author = msg.author
-	resolved = ch.permissions_for(author)
-	return all(getattr(resolved, name, None) == value for name, value in perms.items())
-
-
-def role_or_permissions(ctx, check, **perms):
-	if check_permissions(ctx, perms):
-		return True
-
-	ch = ctx.message.channel
-	author = ctx.message.author
-	if ch.is_private:
-		return False  # can't have roles in PMs
-
-	role = discord.utils.find(check, author.roles)
-	return role is not None
-
-
-def mod_or_permissions(**perms):
-	def predicate(ctx):
-		return role_or_permissions(ctx, lambda r: r.name in ('Bot Mod', 'Bot Admin'), **perms)
-
-	return commands.check(predicate)
-
-
-def admin_or_permissions(**perms):
-	def predicate(ctx):
-		return role_or_permissions(ctx, lambda r: r.name == 'Bot Admin', **perms)
-
-	return commands.check(predicate)
diff --git a/Music-bot/cogs/utils/formats.py b/Music-bot/cogs/utils/formats.py
index 759aa2e03ae7f4b1ecd474f31b052c1d19ecc5af..8089930cceaf29108e7111e8526418185793ac4c 100644
--- a/Music-bot/cogs/utils/formats.py
+++ b/Music-bot/cogs/utils/formats.py
@@ -8,20 +8,4 @@ async def entry_to_code(bot, entries):
     for name, entry in entries:
         output.append(fmt.format(name, entry, width=width))
     output.append('```')
-    await bot.say('\n'.join(output))
-
-
-async def too_many_matches(bot, msg, matches, entry):
-    check = lambda m: m.content.isdigit()
-    await bot.say('There are too many matches... Which one did you mean?')
-    await bot.say('\n'.join(map(entry, enumerate(matches, 1))))
-
-    # only give them 3 tries.
-    for i in range(3):
-        message = await bot.wait_for_message(author=msg.author, channel=msg.channel, check=check)
-        index = int(message.content)
-        try:
-            return matches[index - 1]
-        except:
-            await bot.say('Please give me a valid number. {} tries remaining...'.format(2 - i))
-        raise ValueError('Too many tries. Goodbye.')
\ No newline at end of file
+    await bot.say('\n'.join(output))
\ No newline at end of file