From 743943effdae4fb57d8f0d22f28e180f2571d542 Mon Sep 17 00:00:00 2001 From: rzmk Date: Mon, 26 Jul 2021 12:32:44 -0400 Subject: [PATCH 1/4] Allow stable bot build --- cogs/fun/fun.py | 0 cogs/general/general.py | 0 cogs/moderation/{kick.py => moderationCog.py} | 0 cogs/music/music.py | 0 cogs/{ => music}/musicCog.py | 0 cogs/owner/owner.py | 0 6 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 cogs/fun/fun.py delete mode 100644 cogs/general/general.py rename cogs/moderation/{kick.py => moderationCog.py} (100%) delete mode 100644 cogs/music/music.py rename cogs/{ => music}/musicCog.py (100%) delete mode 100644 cogs/owner/owner.py diff --git a/cogs/fun/fun.py b/cogs/fun/fun.py deleted file mode 100644 index e69de29..0000000 diff --git a/cogs/general/general.py b/cogs/general/general.py deleted file mode 100644 index e69de29..0000000 diff --git a/cogs/moderation/kick.py b/cogs/moderation/moderationCog.py similarity index 100% rename from cogs/moderation/kick.py rename to cogs/moderation/moderationCog.py diff --git a/cogs/music/music.py b/cogs/music/music.py deleted file mode 100644 index e69de29..0000000 diff --git a/cogs/musicCog.py b/cogs/music/musicCog.py similarity index 100% rename from cogs/musicCog.py rename to cogs/music/musicCog.py diff --git a/cogs/owner/owner.py b/cogs/owner/owner.py deleted file mode 100644 index e69de29..0000000 From 0c21b2ee01c262c00d42941f70d2619a62759392 Mon Sep 17 00:00:00 2001 From: rzmk Date: Tue, 27 Jul 2021 13:49:48 -0400 Subject: [PATCH 2/4] Add inventory DB cog and fix music cog --- bot.py | 10 +++++- cogs/info/pingCog.py | 1 + cogs/inventory/inventoryCog.py | 61 ++++++++++++++++++++++++++++++++ cogs/moderation/moderationCog.py | 7 ++-- cogs/music/musicCog.py | 32 ++++++++++------- requirements.txt | 59 +++++++++++++++++++++--------- 6 files changed, 137 insertions(+), 33 deletions(-) create mode 100644 cogs/inventory/inventoryCog.py diff --git a/bot.py b/bot.py index ec91456..b110347 100644 --- a/bot.py +++ b/bot.py @@ -13,12 +13,16 @@ async def on_ready(): print(f'{client.user.name} is ready.') await client.change_presence(activity=discord.Streaming(name="duck pictures.", url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")) +@commands.is_owner() @client.command() async def load(ctx, extension): + """Loads a cog""" client.load_extension(f'cogs.{extension}') - + +@commands.is_owner() @client.command() async def unload(ctx, extension): + """Unloads a cog""" client.unload_extension(f'cogs.{extension}') # Subfolders @@ -46,4 +50,8 @@ for filename in os.listdir('./cogs/owner'): if filename.endswith('.py'): client.load_extension(f'cogs.owner.{filename[:-3]}') +for filename in os.listdir('./cogs/inventory'): + if filename.endswith('.py'): + client.load_extension(f'cogs.inventory.{filename[:-3]}') + client.run(TOKEN) \ No newline at end of file diff --git a/cogs/info/pingCog.py b/cogs/info/pingCog.py index 2c6b071..fdf5c33 100644 --- a/cogs/info/pingCog.py +++ b/cogs/info/pingCog.py @@ -9,6 +9,7 @@ class PingCog(commands.Cog): # Commands @commands.command(aliases=['latency']) async def ping(self, ctx): + """Returns the bot client latency""" await ctx.send(f'Pong! {round(self.client.latency * 1000)}ms') def setup(client): diff --git a/cogs/inventory/inventoryCog.py b/cogs/inventory/inventoryCog.py new file mode 100644 index 0000000..239c0d7 --- /dev/null +++ b/cogs/inventory/inventoryCog.py @@ -0,0 +1,61 @@ +import os +import discord +import DiscordUtils +import asyncio +from google.cloud import firestore +from discord.ext import commands +from dotenv import load_dotenv + +load_dotenv() + +class InventoryCog(commands.Cog): + + def __init__(self, client): + self.client = client + # Commands + + # Get a single item from inventory + @commands.command(aliases=['inv']) + @commands.is_owner() + async def inventory(self, ctx, arg1): + """Get a single item from the inventory database""" + + # Make single input embed + def single_embed(item, id): + embed = discord.Embed(title=item["item_name"], description=id) + if item["item_type"] != "": embed.add_field(name="Item Type", value=item["item_type"], inline=True) + if item["color"] != "": embed.add_field(name="Color", value=item["color"], inline=True) + if item["brand"] != "": embed.add_field(name="Brand", value=item["brand"], inline=True) + if item["model"] != "": embed.add_field(name="Model", value=item["model"], inline=True) + if item["size"] != "": embed.add_field(name="Size", value=item["size"], inline=True) + if item["quantity"] != "": embed.add_field(name="Quantity", value=item["quantity"], inline=True) + if item["box"] != "": embed.add_field(name="Box", value=item["box"], inline=True) + return embed + + # Connect to Firestore DB inventory collection and get the item arg1 as doc + if "INVENTORY_PROJECT_ID" in os.environ and "GOOGLE_APPLICATION_CREDENTIALS" in os.environ: + try: + db = firestore.AsyncClient(project=os.environ.get("INVENTORY_PROJECT_ID")) + inventory_ref = db.collection("inventory").document(arg1) + doc = await inventory_ref.get() + + if doc.exists: + await ctx.send(embed=single_embed(doc.to_dict(), doc.id)) + else: + await ctx.send("That ID doesn't exist!") + except: + await ctx.send("The DB connection is not working.") + elif "INVENTORY_PROJECT_ID" not in os.environ and "GOOGLE_APPLICATION_CREDENTIALS" in os.environ: + await ctx.send("Inventory Project ID not found!") + elif "GOOGLE_APPLICATION_CREDENTIALS" not in os.environ: + await ctx.send("GAPP Credentials not found!") + + @inventory.error + async def inventory_error(self, ctx, error): + if isinstance(error, commands.MissingRequiredArgument): + await ctx.send("Missing required argument! (e.g. d!inventory __10000__)") + if isinstance(error, commands.NotOwner): + await ctx.send("You do not have permissions to run this command.") + +def setup(client): + client.add_cog(InventoryCog(client)) \ No newline at end of file diff --git a/cogs/moderation/moderationCog.py b/cogs/moderation/moderationCog.py index 28f370e..a769e5c 100644 --- a/cogs/moderation/moderationCog.py +++ b/cogs/moderation/moderationCog.py @@ -9,17 +9,18 @@ class ModerationCog(commands.Cog): # Commands @commands.command() @commands.has_permissions(kick_members = True) - async def kick(self, ctx, member : discord.Member, *, reason="No reason provided."): + async def kick(self, ctx, member : commands.MemberConverter, *, reason="No reason provided."): + """Kick a user from the server""" try: await member.kick(reason=reason) await ctx.send(member.mention + " has been kicked.") except: await ctx.send(f"Unable to kick {member.mention}.\nIs {member.mention} at the same role level or higher than {self.client.user.name}?") - @commands.command() @commands.has_permissions(ban_members = True) - async def ban(self, ctx, member : discord.Member, *, reason="No reason provided."): + async def ban(self, ctx, member : commands.MemberConverter, *, reason="No reason provided."): + """Ban a user from the server""" try: await member.ban(reason=reason) await ctx.send(member.mention + " has been banned.") diff --git a/cogs/music/musicCog.py b/cogs/music/musicCog.py index 2dea118..1af5f63 100644 --- a/cogs/music/musicCog.py +++ b/cogs/music/musicCog.py @@ -53,21 +53,30 @@ class MusicCog(commands.Cog): # Commands @commands.command() - async def play(self, ctx, *, url): - """Streams from a url (same as yt, but doesn't predownload)""" + async def play(self, ctx, url): + """Streams from a url""" try: - voiceChannel = discord.utils.get(ctx.guild.voice_channels, guild=ctx.guild) - await voiceChannel.connect() + channel = ctx.author.voice.channel + await channel.connect() except: pass async with ctx.typing(): player = await YTDLSource.from_url(url, loop=self.client.loop, stream=True) ctx.voice_client.play(player, after=lambda e: print(f'Player error: {e}') if e else None) - await ctx.send(f'Now playing: {player.title}') - @commands.command() + @play.error + async def play_error(self, ctx, error): + if isinstance(error, commands.MissingRequiredArgument): + voice = ctx.voice_client + if voice != None and voice.is_paused(): + voice.resume() + else: + await ctx.send("Missing URL!") + + @commands.command(aliases=['disconnect, dc']) async def leave(self, ctx): + """Disconnects bot from the voice channel""" voice = ctx.voice_client if voice.is_connected(): await voice.disconnect() @@ -86,6 +95,7 @@ class MusicCog(commands.Cog): @commands.command() async def pause(self, ctx): + """Pauses audio""" voice = ctx.voice_client if voice.is_playing(): voice.pause() @@ -94,6 +104,7 @@ class MusicCog(commands.Cog): @commands.command() async def resume(self, ctx): + """Resumes currently paused audio""" voice = ctx.voice_client if voice.is_paused(): voice.resume() @@ -109,20 +120,15 @@ class MusicCog(commands.Cog): @commands.command(aliases=['join']) async def connect(self, ctx): + """Connects bot to currently connected voice channel""" channel = ctx.author.voice.channel try: await channel.connect() except: voice = ctx.voice_client - if voice.is_connected(): + if voice.is_connected() and voice.channel != channel: await voice.disconnect() await channel.connect() - else: - await channel.connect() - - '''@commands.command(aliases=['dc','leave']) - async def disconnect(self, ctx): - await ctx.voice_client.disconnect()''' def setup(client): client.add_cog(MusicCog(client)) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index e3cc27d..1fabda0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,16 +1,43 @@ -aiohttp==3.7.4.post0 -async-timeout==3.0.1 -attrs==21.2.0 -cffi==1.14.5 -chardet==4.0.0 -discord==1.0.1 -discord.py==1.7.2 -idna==3.1 -multidict==5.1.0 -pycparser==2.20 -PyNaCl==1.4.0 -python-dotenv==0.17.1 -six==1.16.0 -typing-extensions==3.10.0.0 -yarl==1.6.3 -youtube-dl==2021.5.16 +aiohttp==3.7.4.post0 +async-timeout==3.0.1 +attrs==21.2.0 +cachetools==4.2.2 +certifi==2021.5.30 +cffi==1.14.5 +chardet==4.0.0 +charset-normalizer==2.0.3 +discord==1.0.1 +discord.py==1.7.2 +DiscordUtils==1.3.4 +gcloud==0.18.3 +google-api-core==1.31.0 +google-auth==1.33.1 +google-cloud-core==1.7.1 +google-cloud-firestore==2.2.0 +googleapis-common-protos==1.53.0 +grpcio==1.39.0 +httplib2==0.19.1 +idna==3.1 +jws==0.1.3 +multidict==5.1.0 +oauth2client==4.1.3 +packaging==21.0 +proto-plus==1.19.0 +protobuf==3.17.3 +pyasn1==0.4.8 +pyasn1-modules==0.2.8 +pycparser==2.20 +pycryptodome==3.10.1 +PyNaCl==1.4.0 +pyparsing==2.4.7 +python-dotenv==0.17.1 +python-jwt==2.0.1 +pytz==2021.1 +requests==2.26.0 +requests-toolbelt==0.9.1 +rsa==4.7.2 +six==1.16.0 +typing-extensions==3.10.0.0 +urllib3==1.26.6 +yarl==1.6.3 +youtube-dl==2021.5.16 From 47b584e0890e4ce89a4f8d6e1d963c803a03303d Mon Sep 17 00:00:00 2001 From: rzmk Date: Tue, 27 Jul 2021 13:58:39 -0400 Subject: [PATCH 3/4] Comment unused cogs --- bot.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/bot.py b/bot.py index b110347..2c6f89f 100644 --- a/bot.py +++ b/bot.py @@ -26,13 +26,13 @@ async def unload(ctx, extension): client.unload_extension(f'cogs.{extension}') # Subfolders -for filename in os.listdir('./cogs/fun'): - if filename.endswith('.py'): - client.load_extension(f'cogs.fun.{filename[:-3]}') +# for filename in os.listdir('./cogs/fun'): +# if filename.endswith('.py'): +# client.load_extension(f'cogs.fun.{filename[:-3]}') -for filename in os.listdir('./cogs/general'): - if filename.endswith('.py'): - client.load_extension(f'cogs.general.{filename[:-3]}') +# for filename in os.listdir('./cogs/general'): +# if filename.endswith('.py'): +# client.load_extension(f'cogs.general.{filename[:-3]}') for filename in os.listdir('./cogs/info'): if filename.endswith('.py'): @@ -46,9 +46,9 @@ for filename in os.listdir('./cogs/music'): if filename.endswith('.py'): client.load_extension(f'cogs.music.{filename[:-3]}') -for filename in os.listdir('./cogs/owner'): - if filename.endswith('.py'): - client.load_extension(f'cogs.owner.{filename[:-3]}') +# for filename in os.listdir('./cogs/owner'): +# if filename.endswith('.py'): +# client.load_extension(f'cogs.owner.{filename[:-3]}') for filename in os.listdir('./cogs/inventory'): if filename.endswith('.py'): From f8644bbe1ad1f212814c36f4d04265cc046103ff Mon Sep 17 00:00:00 2001 From: rzmk Date: Tue, 27 Jul 2021 14:13:50 -0400 Subject: [PATCH 4/4] Fix audio command issues --- cogs/music/musicCog.py | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/cogs/music/musicCog.py b/cogs/music/musicCog.py index 1af5f63..8be0488 100644 --- a/cogs/music/musicCog.py +++ b/cogs/music/musicCog.py @@ -55,6 +55,10 @@ class MusicCog(commands.Cog): @commands.command() async def play(self, ctx, url): """Streams from a url""" + + if ctx.author.voice is None: + return await ctx.send("You're not connected to a voice channel.") + try: channel = ctx.author.voice.channel await channel.connect() @@ -77,9 +81,14 @@ class MusicCog(commands.Cog): @commands.command(aliases=['disconnect, dc']) async def leave(self, ctx): """Disconnects bot from the voice channel""" + + if ctx.author.voice is None: + return await ctx.send("You're not connected to a voice channel.") + voice = ctx.voice_client - if voice.is_connected(): - await voice.disconnect() + if voice is not None: + if voice.is_connected(): + await voice.disconnect() else: await ctx.send("The bot is not connected to a voice channel.") @@ -87,6 +96,9 @@ class MusicCog(commands.Cog): async def volume(self, ctx, volume: int): """Changes the player's volume""" + if ctx.author.voice is None: + return await ctx.send("You're not connected to a voice channel.") + if ctx.voice_client is None: return await ctx.send("Not connected to a voice channel.") @@ -96,6 +108,10 @@ class MusicCog(commands.Cog): @commands.command() async def pause(self, ctx): """Pauses audio""" + + if ctx.author.voice is None: + return await ctx.send("You're not connected to a voice channel.") + voice = ctx.voice_client if voice.is_playing(): voice.pause() @@ -105,6 +121,10 @@ class MusicCog(commands.Cog): @commands.command() async def resume(self, ctx): """Resumes currently paused audio""" + + if ctx.author.voice is None: + return await ctx.send("You're not connected to a voice channel.") + voice = ctx.voice_client if voice.is_paused(): voice.resume() @@ -115,12 +135,20 @@ class MusicCog(commands.Cog): async def stop(self, ctx): """Stops and disconnects the bot from voice""" + if ctx.author.voice is None: + return await ctx.send("You're not connected to a voice channel.") + voice = ctx.voice_client - voice.stop() + if voice: + voice.stop() @commands.command(aliases=['join']) async def connect(self, ctx): """Connects bot to currently connected voice channel""" + + if ctx.author.voice is None: + return await ctx.send("You're not connected to a voice channel.") + channel = ctx.author.voice.channel try: await channel.connect()