From 65a504c8821a199dc0f198744f8ff01057a4eb9a Mon Sep 17 00:00:00 2001 From: Benjamin Morgan Date: Sun, 4 Jan 2026 18:18:57 -0700 Subject: [PATCH] Bunch of cleanup --- Dockerfile | 2 +- README.md | 24 ++- mstbot.py | 497 +++++++++++++++++++++++++++-------------------------- schema.sql | 5 +- 4 files changed, 282 insertions(+), 246 deletions(-) diff --git a/Dockerfile b/Dockerfile index 45e977f..d393682 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,4 +11,4 @@ RUN apt update && apt install sqlite3 RUN pip install --upgrade pip && pip install -r requirements.txt ENTRYPOINT [ "/app/entrypoint.sh" ] -CMD [ "python3", "mstbot.py" ] +CMD [ "python3", "-u", "mstbot.py" ] diff --git a/README.md b/README.md index 1721f6f..ebe656b 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,24 @@ +![Static Badge](https://img.shields.io/badge/Bot-Invite-5865F2?style=for-the-badge&logo=discord&link=https%3A%2F%2Fdiscord.com%2Foauth2%2Fauthorize%3Fclient_id%3D911009295947165747%26permissions%3D3088%26response_type%3Dcode%26redirect_uri%3Dhttps%253A%252F%252Fwww.benrmorgan.com%252Fportfolio%252Fminecraft-server-tools-bot%26integration_type%3D0%26scope%3Dmessages.read%2Bbot) # MinecraftStatus -Minecraft Status discord bot +Minecraft Status discord bot that adds status banners to your guild's sidebar. See below for example. + +![Server Status Banners](image.png) + +### Commands +``` +Admin: + announce Turns on player join announcements + cleanup Removes querier and status channels + noannounce Turns off player join announcements + nohours Turns off total player hour display + setup Sets up new Minecraft server querier + showhours Turns on total player hour display +Other: + help Shows this message + lastquery Shows last query time + players Lists online players + status Shows server status + +Type $help command for more info on a command. +You can also type $help category for more info on a category. +``` diff --git a/mstbot.py b/mstbot.py index 3d835e0..892c8b6 100644 --- a/mstbot.py +++ b/mstbot.py @@ -1,9 +1,10 @@ -# TODO: Change hours column to boolean, drop times table, make it a column in servers -# TODO: prevent sql injection +# TODO: in readme, add badge for guild count, total player count +# TODO: make dev bot for testing +# TODO: handle wait=301 rate limits more cleanly # TODO: annotate return types everywhere # TODO: split cogs into separate files, add utils file, remove globals +# TODO: wrap all SQL queries with a func to determine if server has been set up or not. If fetchone returns None, log helpful message to run $setup. # TODO: save invite link to README and show query port enable instructions -# TODO: https://discord.com/oauth2/authorize?client_id=911009295947165747&permissions=3088&response_type=code&redirect_uri=https%3A%2F%2Fwww.benrmorgan.com%2Fportfolio%2Fminecraft-server-tools-bot&integration_type=0&scope=messages.read+bot # TODO: Feature: allow discord users to associate their mc usernames, change server nickname? # TODO: Feature: allow other users to query playtime by username, default to their own. This and above require new columns in names table. @@ -13,6 +14,7 @@ import re import socket import unicodedata +from contextlib import contextmanager from datetime import datetime, timezone from typing import Union, List @@ -31,10 +33,11 @@ servers = [] @bot.event async def on_ready(): print(f'Logged in as {bot.user}') - mydb, cursor = connect() - cursor.execute("SELECT id, ip, announce_joins, announce_joins_id FROM servers") - rows = cursor.fetchall() + with sqlite_conn() as conn: + rows = conn.execute( + "SELECT id, ip, announce_joins, announce_joins_id FROM servers" + ).fetchall() for row in rows: if get_server_by_id(row[0]) is None: @@ -51,14 +54,13 @@ async def on_ready(): @bot.event async def on_command_error(ctx: commands.Context, error: commands.CommandError): command = ctx.message.content.split()[0][1:] # Extract command name - prefix = ctx.prefix if isinstance(error, commands.CommandNotFound): - await safe_send(ctx, f'Command "{command}" does not exist. Use `{ctx.prefix}help` for available commands.') + await safe_send(f'Command "{command}" does not exist. Use `{ctx.prefix}help` for available commands.', ctx) elif isinstance(error, commands.MissingRequiredArgument): await log(ctx, f'Command "{command}" is missing required arguments. Use `{ctx.prefix}help {command}` for details.') elif isinstance(error, commands.MissingPermissions): - await safe_send(ctx, f'You lack permissions: {", ".join(error.missing_perms)}.') + await safe_send(f'You lack permissions: {", ".join(error.missing_perms)}.', ctx) elif isinstance(error, commands.CommandInvokeError) and isinstance(error.original, socket.gaierror): await log(ctx, "Could not connect, is the server down?") else: @@ -87,16 +89,16 @@ class Admin(commands.Cog): except ConnectionRefusedError: await log(ctx, "Setup query failed, server down?") else: - mydb, cursor = connect() + with sqlite_conn() as conn: + conn.execute(""" + INSERT INTO servers (id, ip, port) + VALUES (?, ?, ?) + ON CONFLICT(id) DO UPDATE SET + ip = excluded.ip, + port = excluded.port + """, (ctx.guild.id, val_ip, val_port)) - cursor.execute(f"INSERT INTO servers (id, ip, port) VALUES({str(ctx.guild.id)}, \"{val_ip}\", {str(port)}) ON CONFLICT(id) DO UPDATE SET ip=\"{val_ip}\", port={str(port)}") - - setMCNames(ctx.guild.id, cursor, names) - - cursor.execute(f"INSERT INTO times (id) VALUES({ctx.guild.id}) ON CONFLICT(id) DO UPDATE SET id=id;") - - mydb.commit() - mydb.close() + setMCNames(ctx.guild.id, conn, names) if annChanID is None: await setAnn(ctx, False) @@ -129,34 +131,12 @@ class Admin(commands.Cog): @commands.command(brief="Turns on total player hour display", description="Turns on total player hour display.") @commands.has_permissions(administrator=True) async def showhours(self, ctx: discord.ext.commands.context.Context): - await setHours(ctx, True) + await setShowHours(ctx, True) @commands.command(brief="Turns off total player hour display", description="Turns off total player hour display.") @commands.has_permissions(administrator=True) async def nohours(self, ctx: discord.ext.commands.context.Context): - await setHours(ctx, False) - - # @commands.command() - # async def notif(ctx: discord.ext.commands.context.Context, kind: Union[str, None] = None): - # if kind is None: - # await safe_send(ctx, "The notification options are: \n1. joins") - # else: - # name = "" - # if kind.lower() == "joins": - # name = "Status Joins" - # - # if name != "": - # await addrole(ctx, name) - # await log(ctx, "Gave", name, "role to", ctx.message.author.name) - # - # - # async def addrole(ctx: discord.ext.commands.context.Context, name: str): - # member = ctx.message.author - # role = get(member.guild.roles, name=name) - # if role is None: - # role = await member.guild.create_role(name=name) - # - # await member.add_roles(role) + await setShowHours(ctx, False) class Other(commands.Cog): @@ -167,33 +147,29 @@ class Other(commands.Cog): @commands.command(brief="Shows server status", description="Shows server status.") async def status(self, ctx: discord.ext.commands.context.Context): - mydb, cursor = connect() - ip, port = getMCIP(ctx.guild.id, cursor) - mc = JavaServer(ip, port) - - - if mc is None: - await safe_send("There is no server query set up. Run the `setup` command to get started.", ctx=ctx) - else: - players, max, _, motd = await getStatus(mc) - - seconds = getPersonSeconds(ctx.guild.id, cursor) - seconds = seconds % (24 * 3600) - hour = seconds // 3600 - seconds %= 3600 - minutes = seconds // 60 - seconds %= 60 - - await safe_send("Status:\n " + ip + "\n " + motd.to_plain() + "\n\n Players: " + str(players) + "/" + str(max) + "\n Total Player Time: " + "%d:%02d:%02d" % (hour, minutes, seconds), ctx=ctx, format="```") + with sqlite_conn() as conn: + ip, port = getMCIP(ctx.guild.id, conn) + mc = JavaServer(ip, port) - mydb.close() + if mc is None: + await safe_send("There is no server query set up. Run the `setup` command to get started.", ctx=ctx) + else: + players, max, _, motd = await getStatus(mc) + + seconds = getPersonSeconds(ctx.guild.id, conn) + seconds = seconds % (24 * 3600) + hour = seconds // 3600 + seconds %= 3600 + minutes = seconds // 60 + seconds %= 60 + + await safe_send("Status:\n " + ip + "\n " + motd.to_plain() + "\n\n Players: " + str(players) + "/" + str(max) + "\n Total Player Time: " + "%d:%02d:%02d" % (hour, minutes, seconds), ctx=ctx, format="```") @commands.command(brief="Lists online players", description="Lists online players.") async def players(self, ctx: discord.ext.commands.context.Context): - mydb, cursor = connect() - ip, port = getMCIP(ctx.guild.id, cursor) - mc = JavaServer(ip, port) - mydb.close() + with sqlite_conn() as conn: + ip, port = getMCIP(ctx.guild.id, conn) + mc = JavaServer(ip, port) if mc is None: await safe_send("There is no server query set up. Run the `setup` command to get started.", ctx=ctx) @@ -209,11 +185,10 @@ class Other(commands.Cog): @commands.command(brief="Shows last query time", description="Shows last query time. Useful for debugging server connection issues.") async def lastquery(self, ctx: discord.ext.commands.context.Context): - mydb, cursor = connect() - ip, port = getMCIP(ctx.guild.id, cursor) - mc = JavaServer(ip, port) - last = getMCQueryTime(ctx.guild.id, cursor) - mydb.close() + with sqlite_conn() as conn: + ip, port = getMCIP(ctx.guild.id, conn) + mc = JavaServer(ip, port) + last = getMCQueryTime(ctx.guild.id, conn) if mc is None: await safe_send("There is no server query set up. Run the `setup` command to get started.", ctx=ctx) @@ -236,15 +211,20 @@ async def setAnn(ctx: discord.ext.commands.context.Context, ann: bool, cid: Unio await log(ctx, "Channel", str(cid), "does not exist.") return - mydb, cursor = connect() - ip, _ = getMCIP(ctx.guild.id, cursor) + with sqlite_conn() as conn: + ip, _ = getMCIP(ctx.guild.id, conn) - cursor.execute( - "UPDATE servers SET announce_joins=" + str((0, 1)[ann]) + ", announce_joins_id=" + ("NULL", str(cid))[ - ann] + " WHERE id=" + str(ctx.guild.id)) - - mydb.commit() - mydb.close() + conn.execute(""" + UPDATE servers + SET + announce_joins = ?, + announce_joins_id = ? + WHERE id = ? + """, ( + ann, + cid if ann else None, + ctx.guild.id + )) await log(ctx, ( "Not announcing when a player joins " + ip + ".", @@ -252,20 +232,23 @@ async def setAnn(ctx: discord.ext.commands.context.Context, ann: bool, cid: Unio ann]) -async def setHours(ctx: discord.ext.commands.context.Context, hours: bool): - mydb, cursor = connect() - ip, _ = getMCIP(ctx.guild.id, cursor) +async def setShowHours(ctx: discord.ext.commands.context.Context, show_hours: bool): + with sqlite_conn() as conn: + ip, _ = getMCIP(ctx.guild.id, conn) - cursor.execute( - f"UPDATE servers SET hours={str((0, 1)[hours])} WHERE id={str(ctx.guild.id)}") - - mydb.commit() - mydb.close() + conn.execute(""" + UPDATE servers + SET show_hours = ? + WHERE id = ? + """, ( + show_hours, + ctx.guild.id + )) await log(ctx, ( "Not displaying total player hours for " + ip + ".", "Displaying total player hours for " + ip + ".")[ - hours] + " Please wait a moment for channel updates to take effect.") + show_hours] + " Please wait a moment for channel updates to take effect.") async def log(ctx: commands.Context, *msg: str): @@ -349,77 +332,110 @@ async def getStatus(serv: JavaServer): return p, m, n, d -def connect(): - mydb = sqlite3.connect('/data/mstbot.db') - - cursor = mydb.cursor() - return mydb, cursor +@contextmanager +def sqlite_conn(): + conn = sqlite3.connect('/data/mstbot.db') + try: + # per-connection PRAGMAs + conn.execute("PRAGMA foreign_keys = ON") + conn.execute("PRAGMA busy_timeout = 5000") + yield conn + conn.commit() + except Exception: + conn.rollback() + raise + finally: + # run on close + conn.execute("PRAGMA optimize") + conn.close() -def getMCIP(sid: int, cursor: sqlite3.Cursor): - cursor.execute("SELECT ip, port FROM servers WHERE id=" + str(sid)) - row = cursor.fetchone() +def getMCIP(sid: int, conn: sqlite3.Connection): + row = conn.execute( + "SELECT ip, port FROM servers WHERE id = ?", + (sid,) + ).fetchone() + ip = row[0] port = row[1] return ip, port -def getMCNames(sid: int, cursor: sqlite3.Cursor): - cursor.execute("SELECT name FROM names WHERE id=" + str(sid)) - rows = cursor.fetchall() +def getMCNames(sid: int, conn: sqlite3.Connection): + rows = conn.execute( + "SELECT name FROM names WHERE id = ?", + (sid,) + ).fetchall() return [row[0] for row in rows] -def getMCQueryTime(sid: int, cursor: sqlite3.Cursor): - cursor.execute("SELECT last_query FROM servers WHERE id=" + str(sid)) - tstr = cursor.fetchone()[0] +def getMCQueryTime(sid: int, conn: sqlite3.Connection): + tstr = conn.execute( + "SELECT last_query FROM servers WHERE id = ?", + (sid,) + ).fetchone()[0] if tstr is None: return tstr return datetime.strptime(tstr, '%Y-%m-%d %H:%M:%S') -def getPersonSeconds(sid: int, cursor: sqlite3.Cursor): - cursor.execute("SELECT time FROM times WHERE id=" + str(sid)) - tstr = cursor.fetchone()[0] +def getPersonSeconds(sid: int, conn: sqlite3.Connection): + cols = conn.execute( + f"SELECT SUM(seconds) FROM times WHERE id = ? GROUP BY id", + (sid,) + ).fetchone() + if cols is not None: + return cols[0] - return int(tstr) + return 0 -def getShowHours(sid: int, cursor: sqlite3.Cursor): - cursor.execute("SELECT hours FROM servers WHERE id=" + str(sid)) - tstr = cursor.fetchone()[0] +def getShowHours(sid: int, conn: sqlite3.Connection): + show_hours = conn.execute( + "SELECT show_hours FROM servers WHERE id = ?", + (sid,) + ).fetchone()[0] - return bool(tstr) + return show_hours -def getMCJoinAnnounce(sid: int, cursor: sqlite3.Cursor): - cursor.execute("SELECT announce_joins, announce_joins_id FROM servers WHERE id=" + str(sid)) - row = cursor.fetchone() +def getMCJoinAnnounce(sid: int, conn: sqlite3.Connection): + row = conn.execute( + "SELECT announce_joins, announce_joins_id FROM servers WHERE id = ?", + (sid,) + ).fetchone() ann = row[0] cid = row[1] return ann, cid -def setMCNames(sid: int, cursor: sqlite3.Cursor, names: List[str]): - cursor.execute("DELETE FROM names WHERE id=" + str(sid)) +def setMCNames(sid: int, conn: sqlite3.Connection, names: List[str]): + conn.execute("DELETE FROM names WHERE id = ?", (sid,)) - if len(names) > 0: - qStr = "" - for name in names: - qStr += "(" + str(sid) + ",\"" + name + "\")," + if names: + rows = [(sid, name) for name in names] + conn.executemany("INSERT INTO names (id, name) VALUES (?, ?)", rows) - qStr = qStr[:-1] + ";" - - cursor.execute("INSERT INTO names (id, name) VALUES " + qStr) +def setMCQueryTime(sid: int, conn: sqlite3.Connection, dt: datetime): + conn.execute(""" + UPDATE servers + SET last_query = ? + WHERE id = ? + """, ( + dt.strftime('%Y-%m-%d %H:%M:%S'), + sid + )) -def setMCQueryTime(sid: int, cursor: sqlite3.Cursor, dt: datetime): - cursor.execute("UPDATE servers SET last_query=\"" + dt.strftime('%Y-%m-%d %H:%M:%S') + "\" WHERE id=" + str(sid)) - -def incrementPersonSeconds(sid: int, cursor: sqlite3.Cursor, seconds: int): - cursor.execute(f"UPDATE times SET time=time+{seconds} WHERE id={str(sid)};") +def incrementPersonSeconds(sid: int, user: str, conn: sqlite3.Connection, seconds: float): + conn.execute(""" + INSERT INTO times (id, name, seconds) + VALUES (?, ?, ?) + ON CONFLICT(id, name) DO UPDATE SET + seconds = times.seconds + excluded.seconds + """, (sid, user, seconds)) async def do_bot_cleanup(sid: int, ctx: Union[discord.ext.commands.context.Context, None] = None): if sid in servers: @@ -440,16 +456,13 @@ async def do_bot_cleanup(sid: int, ctx: Union[discord.ext.commands.context.Conte except discord.errors.Forbidden: print(currServ.name, "Error: I don't have permission to delete channels.") - mydb, cursor = connect() - ip, port = getMCIP(sid, cursor) - mc = JavaServer(ip, port) + with sqlite_conn() as conn: + ip, port = getMCIP(sid, conn) + mc = JavaServer(ip, port) - cursor.execute("DELETE FROM servers WHERE id=" + str(sid)) - cursor.execute("DELETE FROM names WHERE id=" + str(sid)) - cursor.execute("DELETE FROM times WHERE id=" + str(sid)) - - mydb.commit() - mydb.close() + conn.execute("DELETE FROM servers WHERE id = ?", (sid,)) + conn.execute("DELETE FROM names WHERE id = ?", (sid,)) + conn.execute("DELETE FROM times WHERE id = ?", (sid,)) if ctx is None: print("Cleaned up", sid, ".") @@ -496,120 +509,82 @@ async def status_task(sid: int): print(get_server_by_id(sid).name, "is not querying. Ending task.") return - mydb, cursor = connect() - ip, port = getMCIP(sid, cursor) - mc = JavaServer(ip, port) - currServ = get_server_by_id(sid) - wait = 10 + with sqlite_conn() as conn: + ip, port = getMCIP(sid, conn) + mc = JavaServer(ip, port) + currServ = get_server_by_id(sid) + wait = 10 - if not ip == "" and currServ is not None: - try: - oldNames = getMCNames(sid, cursor) - players, max, names, _ = await getStatus(mc) - lastTime = getMCQueryTime(sid, cursor) - lastSeconds = getPersonSeconds(sid, cursor) + if not ip == "" and currServ is not None: + try: + oldNames = getMCNames(sid, conn) + players, max, names, _ = await getStatus(mc) + lastTime = getMCQueryTime(sid, conn) + lastSeconds = getPersonSeconds(sid, conn) - currTime = datetime.now(timezone.utc) - if lastTime is None: - lastTime = currTime - else: - lastTime = lastTime.replace(tzinfo=timezone.utc) - - print(currServ.name, "Query:", ip, str(players) + "/" + str(max), datetime.now(timezone.utc).strftime("%H:%M:%S"), - str(currTime - lastTime)) + currTime = datetime.now(timezone.utc) + if lastTime is None: + lastTime = currTime + else: + lastTime = lastTime.replace(tzinfo=timezone.utc) - setMCNames(sid, cursor, names) - setMCQueryTime(sid, cursor, currTime) - if not first_iter: - incrementPersonSeconds(sid, cursor, len(names) * (currTime - lastTime).total_seconds()) + deltaSeconds = (currTime - lastTime).total_seconds() + + print(currServ.name, "Query:", ip, str(players) + "/" + str(max), datetime.now(timezone.utc).strftime("%H:%M:%S"), + str(deltaSeconds)) - announceJoin, annChanId = getMCJoinAnnounce(sid, cursor) - annRole = None + setMCNames(sid, conn, names) + setMCQueryTime(sid, conn, currTime) + if not first_iter: + for name in names: + incrementPersonSeconds(sid, name, conn, deltaSeconds) - if announceJoin and annChanId is not None: - jNames = list(set(names) - set(oldNames)) - for name in jNames: - aChannels = find_channels(serv=currServ, chanid=int(annChanId)) + announceJoin, annChanId = getMCJoinAnnounce(sid, conn) + annRole = None - if len(aChannels) > 0: - if annRole is None: - await safe_send(name + " joined the game!", chan=aChannels[0]) - else: - await safe_send("<@&" + str(annRole.id) + "> " + name + " joined the game!", - chan=aChannels[0]) + if announceJoin and annChanId is not None: + jNames = list(set(names) - set(oldNames)) + for name in jNames: + aChannels = find_channels(serv=currServ, chanid=int(annChanId)) - print(currServ.name, "Announced player(s) join.") + if len(aChannels) > 0: + if annRole is None: + await safe_send(name + " joined the game!", chan=aChannels[0]) + else: + await safe_send("<@&" + str(annRole.id) + "> " + name + " joined the game!", + chan=aChannels[0]) - except asyncio.exceptions.TimeoutError: - print(currServ.name, "Timeout, server lagging?") - players = -1 - lastSeconds = -1 + print(currServ.name, "Announced player(s) join.") - except (ConnectionRefusedError, socket.gaierror): - print(currServ.name, "Cannot connect to server, down?") - players = -1 - lastSeconds = -1 + except asyncio.exceptions.TimeoutError: + print(currServ.name, "Timeout, server lagging?") + players = -1 + lastSeconds = -1 - iChannels = find_channels(serv=currServ, channame="IP: ", channamesearch="in", chantype=discord.ChannelType.voice) - pChannels = find_channels(serv=currServ, channame="Players: ", channamesearch="in", - chantype=discord.ChannelType.voice) - tChannels = find_channels(serv=currServ, channame="Player Hrs: ", channamesearch="in", - chantype=discord.ChannelType.voice) + except (ConnectionRefusedError, socket.gaierror): + print(currServ.name, "Cannot connect to server, down?") + players = -1 + lastSeconds = -1 - overwrites = { - currServ.default_role: discord.PermissionOverwrite(connect=False, view_channel=True), - currServ.me: discord.PermissionOverwrite(connect=True, view_channel=True, manage_channels=True) - } + iChannels = find_channels(serv=currServ, channame="IP: ", channamesearch="in", chantype=discord.ChannelType.voice) + pChannels = find_channels(serv=currServ, channame="Players: ", channamesearch="in", + chantype=discord.ChannelType.voice) + tChannels = find_channels(serv=currServ, channame="Player Hrs: ", channamesearch="in", + chantype=discord.ChannelType.voice) - if len(iChannels) > 0: - lastIPName = iChannels[0].name + overwrites = { + currServ.default_role: discord.PermissionOverwrite(connect=False, view_channel=True), + currServ.me: discord.PermissionOverwrite(connect=True, view_channel=True, manage_channels=True) + } - ipStr = "IP: " + ip - if lastIPName != ipStr: - try: - print(currServ.name, "Update: Ip changed!") - await iChannels[0].edit(name=ipStr) - wait = 301 - except discord.errors.Forbidden: - print(currServ.name, - "Error: I don't have permission to edit channels. Try deleting the channels I create. Then, run the `setup` command again.") - await do_bot_cleanup(sid) - return - else: - await currServ.create_voice_channel("IP: " + ip, overwrites=overwrites) + if len(iChannels) > 0: + lastIPName = iChannels[0].name - if len(pChannels) > 0: - lastPName = pChannels[0].name - - if players == -1: - pStr = lastPName - else: - pStr = "Players: " + str(players) + "/" + str(max) - - if lastPName != pStr: - try: - print(currServ.name, "Update: Players changed!") - await pChannels[0].edit(name=pStr) - wait = 301 - except discord.errors.Forbidden: - print(currServ.name, - "Error: I don't have permission to edit channels. Try deleting the channels I create. Then, run the `setup` command again.") - await do_bot_cleanup(sid) - return - else: - await currServ.create_voice_channel(f"Players: {str(players)}/{str(max)}", - overwrites=overwrites) - - do_show_hours = getShowHours(sid, cursor) - if do_show_hours and not first_iter and lastSeconds != -1: - tStr = "Player Hrs: " + str(round((lastSeconds + len(names) * (currTime - lastTime).total_seconds())/3600)) - if len(tChannels) > 0: - lastTName = tChannels[0].name - - if lastTName != tStr: + ipStr = "IP: " + ip + if lastIPName != ipStr: try: - print(currServ.name, "Update: Time changed!") - await tChannels[0].edit(name=tStr) + print(currServ.name, "Update: Ip changed!") + await iChannels[0].edit(name=ipStr) wait = 301 except discord.errors.Forbidden: print(currServ.name, @@ -617,15 +592,53 @@ async def status_task(sid: int): await do_bot_cleanup(sid) return else: - await currServ.create_voice_channel(tStr, - overwrites=overwrites) - elif not do_show_hours: - if len(tChannels) > 0: - for channel in tChannels: - await channel.delete() + await currServ.create_voice_channel("IP: " + ip, overwrites=overwrites) - mydb.commit() - mydb.close() + if len(pChannels) > 0: + lastPName = pChannels[0].name + + if players == -1: + pStr = lastPName + else: + pStr = "Players: " + str(players) + "/" + str(max) + + if lastPName != pStr: + try: + print(currServ.name, "Update: Players changed!") + await pChannels[0].edit(name=pStr) + wait = 301 + except discord.errors.Forbidden: + print(currServ.name, + "Error: I don't have permission to edit channels. Try deleting the channels I create. Then, run the `setup` command again.") + await do_bot_cleanup(sid) + return + else: + await currServ.create_voice_channel(f"Players: {str(players)}/{str(max)}", + overwrites=overwrites) + + do_show_hours = getShowHours(sid, conn) + if do_show_hours and not first_iter and lastSeconds != -1: + tStr = "Player Hrs: " + str(round(getPersonSeconds(sid, conn)/3600)) + if len(tChannels) > 0: + lastTName = tChannels[0].name + + if lastTName != tStr: + try: + print(currServ.name, "Update: Time changed!") + await tChannels[0].edit(name=tStr) + wait = 301 + except discord.errors.Forbidden: + print(currServ.name, + "Error: I don't have permission to edit channels. Try deleting the channels I create. Then, run the `setup` command again.") + await do_bot_cleanup(sid) + return + else: + await currServ.create_voice_channel(tStr, + overwrites=overwrites) + elif not do_show_hours: + if len(tChannels) > 0: + for channel in tChannels: + await channel.delete() await asyncio.sleep(wait) first_iter = False diff --git a/schema.sql b/schema.sql index 18bf241..4fb9531 100644 --- a/schema.sql +++ b/schema.sql @@ -1,3 +1,4 @@ +PRAGMA journal_mode = WAL; CREATE TABLE names (id INTEGER NOT NULL, name TEXT NOT NULL, UNIQUE (id, name)); -CREATE TABLE times (id INTEGER NOT NULL PRIMARY KEY, time NOT NULL DEFAULT 0) WITHOUT ROWID; -CREATE TABLE servers (id INTEGER PRIMARY KEY, ip TEXT NOT NULL, port INTEGER NOT NULL DEFAULT 25565, last_query TIMESTAMP, hours REAL NOT NULL DEFAULT 0, announce_joins BOOLEAN NOT NULL DEFAULT FALSE, announce_joins_id INTEGER) WITHOUT ROWID; \ No newline at end of file +CREATE TABLE times (id INTEGER NOT NULL, name TEXT NOT NULL, seconds REAL NOT NULL DEFAULT 0, UNIQUE (id, name)); +CREATE TABLE servers (id INTEGER PRIMARY KEY, ip TEXT NOT NULL, port INTEGER NOT NULL DEFAULT 25565, last_query TIMESTAMP, show_hours BOOLEAN NOT NULL DEFAULT FALSE, announce_joins BOOLEAN NOT NULL DEFAULT FALSE, announce_joins_id INTEGER) WITHOUT ROWID; \ No newline at end of file