diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2549b3d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +config.env diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..da232e1 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +FROM python:3.9 + +# Install dependencies +COPY requirements.txt . +RUN pip3 install -r requirements.txt + +# Copy source +COPY . . + +# Run app +CMD ["python", "./voicecreate.py"] diff --git a/README.md b/README.md index 0bb5700..1095e6a 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,14 @@ https://voicemaster.xyz/ # How to setup the bot: +## Docker Compose + +1. Copy `config.env.default`, rename it to `config.env` and insert your bot token + +2. Execute `docker compose up -d` + +## Bare Metal + 1.Download python using the following link: https://www.python.org/downloads/ diff --git a/cogs/voice.py b/cogs/voice.py index 31586a6..f967429 100644 --- a/cogs/voice.py +++ b/cogs/voice.py @@ -1,13 +1,20 @@ -import discord -import asyncio +import discord, asyncio, sqlite3, os from discord.ext import commands -import sqlite3 class voice(commands.Cog): def __init__(self, bot): self.bot = bot + conn = sqlite3.connect('voice.db') + c = conn.cursor() + c.execute("CREATE TABLE IF NOT EXISTS 'voiceChannel' ('userID' INTEGER, 'voiceID' INTEGER);") + c.execute("CREATE TABLE IF NOT EXISTS 'guild' ('guildID' INTEGER, 'ownerID' INTEGER, 'voiceChannelID' INTEGER, 'voiceCategoryID' INTEGER);") + c.execute("CREATE TABLE IF NOT EXISTS 'userSettings' ('userID' INTEGER, 'channelName' TEXT, 'channelLimit' INTEGER);") + c.execute("CREATE TABLE IF NOT EXISTS 'guildSettings' ('guildID' INTEGER, 'channelName' TEXT, 'channelLimit' INTEGER);") + conn.commit() + conn.close() + @commands.Cog.listener() async def on_voice_state_update(self, member, before, after): conn = sqlite3.connect('voice.db') @@ -27,7 +34,7 @@ async def on_voice_state_update(self, member, before, after): pass else: await member.send("Creating channels too quickly you've been put on a 15 second cooldown!") - await asyncio.sleep(15) + return c.execute("SELECT voiceCategoryID FROM guild WHERE guildID = ?", (guildID,)) voice=c.fetchone() c.execute("SELECT channelName, channelLimit FROM userSettings WHERE userID = ?", (member.id,)) @@ -96,7 +103,7 @@ async def setup(self, ctx): c = conn.cursor() guildID = ctx.guild.id id = ctx.author.id - if ctx.author.id == ctx.guild.owner_id or ctx.author.id == 151028268856770560: + if ctx.author.id == ctx.guild.owner_id or ctx.author.id == os.getenv('DISCORD_ADMIN'): def check(m): return m.author.id == ctx.author.id await ctx.channel.send("**You have 60 seconds to answer each question!**") @@ -133,7 +140,7 @@ def check(m): async def setlimit(self, ctx, num): conn = sqlite3.connect('voice.db') c = conn.cursor() - if ctx.author.id == ctx.guild.owner.id or ctx.author.id == 151028268856770560: + if ctx.author.id == ctx.guild.owner.id or ctx.author.id == os.getenv('DISCORD_ADMIN'): c.execute("SELECT * FROM guildSettings WHERE guildID = ?", (ctx.guild.id,)) voice=c.fetchone() if voice is None: @@ -252,6 +259,54 @@ async def limit(self, ctx, limit): conn.commit() conn.close() + @voice.command() + async def purge(self, ctx): + conn = sqlite3.connect('voice.db') + c = conn.cursor() + guild = ctx.message.guild + guildID = ctx.guild.id + id = ctx.author.id + if ctx.author.id == ctx.guild.owner_id or ctx.author.id == os.getenv('DISCORD_ADMIN'): + def check(m): + return m.author.id == ctx.author.id + await ctx.channel.send("**Do you really want to purge everything?** You have 60 seconds to type YES/Y") + try: + confirm = await self.bot.wait_for('message', check=check, timeout = 60.0) + except asyncio.TimeoutError: + await ctx.channel.send('Took too long to answer!') + else: + if confirm.content.lower() == "yes" or confirm.content.lower() == "y": + c.execute('SELECT * FROM voiceChannel') + for row in c: + voiceID = int(row[1]) + existing_channel = discord.utils.get(guild.channels, id=voiceID) + if existing_channel is not None: + await existing_channel.delete() + + c.execute('DELETE FROM voiceChannel WHERE voiceID=?', (voiceID,)) + await ctx.channel.send(f'Channel with ID "{voiceID}" purged') + + c.execute("SELECT * FROM guild WHERE guildID = ?", (guildID,)) + res=c.fetchone() + del_voiceChannelID = res[2] + del_voiceCategoryID = res[3] + + existing_channel = discord.utils.get(guild.channels, id=del_voiceChannelID) + if existing_channel is not None: + await existing_channel.delete() + + existing_channel = discord.utils.get(guild.channels, id=del_voiceCategoryID) + if existing_channel is not None: + await existing_channel.delete() + + c.execute('DELETE FROM guild WHERE guildID=?', (guildID,)) + await ctx.channel.send("**Everything purged!**") + else: + await ctx.channel.send('abort') + else: + await ctx.channel.send(f"{ctx.author.mention} only the owner of the server can setup the bot!") + conn.commit() + conn.close() @voice.command() async def name(self, ctx,*, name): diff --git a/compose.yml b/compose.yml new file mode 100644 index 0000000..f9d6eea --- /dev/null +++ b/compose.yml @@ -0,0 +1,6 @@ +services: + app: + build: . + env_file: "config.env" + volumes: + - ${PWD}/voice.db:/voice.db diff --git a/config.env.default b/config.env.default new file mode 100644 index 0000000..f4ae4c6 --- /dev/null +++ b/config.env.default @@ -0,0 +1,2 @@ +DISCORD_TOKEN=TOKEN123 +DISCORD_ADMIN=151028268856770560 diff --git a/requirements.txt b/requirements.txt index 844f49a..a41d83f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ discord.py +python-dotenv diff --git a/voice.db b/voice.db index 0669f35..87b3f33 100644 Binary files a/voice.db and b/voice.db differ diff --git a/voicecreate.py b/voicecreate.py index 02f40f7..169e89e 100644 --- a/voicecreate.py +++ b/voicecreate.py @@ -1,7 +1,17 @@ -import discord +import discord, traceback, sys, os, dotenv from discord.ext import commands -import traceback -import sys + +# Load environment variables from .env file (if present) +dotenv.load_dotenv(dotenv_path="config.env") + +# Ensure all required environment variables are set +if not os.getenv('DISCORD_TOKEN'): + print('[error]: `DISCORD_TOKEN` environment variable required') + sys.exit(1) + +if not os.getenv('DISCORD_ADMIN'): + print('[error]: `DISCORD_ADMIN` environment variable required') + sys.exit(1) intents = discord.Intents.default() #Message content intent needs to be enabled in the developer portal for your chosen bot. @@ -11,8 +21,6 @@ bot.remove_command("help") -DISCORD_TOKEN = 'Enter Discord Token here' - initial_extensions = ['cogs.voice'] @bot.event @@ -21,7 +29,7 @@ async def on_ready(): print(bot.user.name) print(bot.user.id) print('------') - + for extension in initial_extensions: try: await bot.load_extension(extension) @@ -30,4 +38,4 @@ async def on_ready(): print(f'Failed to load extension {extension}.', file=sys.stderr) traceback.print_exc() -bot.run(DISCORD_TOKEN) +bot.run(os.getenv('DISCORD_TOKEN'))