Bunch of cleanup

This commit is contained in:
Benjamin Morgan 2026-01-04 18:18:57 -07:00
parent dee736bd54
commit 65a504c882
4 changed files with 282 additions and 246 deletions

View file

@ -11,4 +11,4 @@ RUN apt update && apt install sqlite3
RUN pip install --upgrade pip && pip install -r requirements.txt RUN pip install --upgrade pip && pip install -r requirements.txt
ENTRYPOINT [ "/app/entrypoint.sh" ] ENTRYPOINT [ "/app/entrypoint.sh" ]
CMD [ "python3", "mstbot.py" ] CMD [ "python3", "-u", "mstbot.py" ]

View file

@ -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 # 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.
```

497
mstbot.py
View file

@ -1,9 +1,10 @@
# TODO: Change hours column to boolean, drop times table, make it a column in servers # TODO: in readme, add badge for guild count, total player count
# TODO: prevent sql injection # TODO: make dev bot for testing
# TODO: handle wait=301 rate limits more cleanly
# TODO: annotate return types everywhere # TODO: annotate return types everywhere
# TODO: split cogs into separate files, add utils file, remove globals # 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: 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 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. # 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 socket
import unicodedata import unicodedata
from contextlib import contextmanager
from datetime import datetime, timezone from datetime import datetime, timezone
from typing import Union, List from typing import Union, List
@ -31,10 +33,11 @@ servers = []
@bot.event @bot.event
async def on_ready(): async def on_ready():
print(f'Logged in as {bot.user}') print(f'Logged in as {bot.user}')
mydb, cursor = connect()
cursor.execute("SELECT id, ip, announce_joins, announce_joins_id FROM servers") with sqlite_conn() as conn:
rows = cursor.fetchall() rows = conn.execute(
"SELECT id, ip, announce_joins, announce_joins_id FROM servers"
).fetchall()
for row in rows: for row in rows:
if get_server_by_id(row[0]) is None: if get_server_by_id(row[0]) is None:
@ -51,14 +54,13 @@ async def on_ready():
@bot.event @bot.event
async def on_command_error(ctx: commands.Context, error: commands.CommandError): async def on_command_error(ctx: commands.Context, error: commands.CommandError):
command = ctx.message.content.split()[0][1:] # Extract command name command = ctx.message.content.split()[0][1:] # Extract command name
prefix = ctx.prefix
if isinstance(error, commands.CommandNotFound): 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): elif isinstance(error, commands.MissingRequiredArgument):
await log(ctx, f'Command "{command}" is missing required arguments. Use `{ctx.prefix}help {command}` for details.') await log(ctx, f'Command "{command}" is missing required arguments. Use `{ctx.prefix}help {command}` for details.')
elif isinstance(error, commands.MissingPermissions): 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): elif isinstance(error, commands.CommandInvokeError) and isinstance(error.original, socket.gaierror):
await log(ctx, "Could not connect, is the server down?") await log(ctx, "Could not connect, is the server down?")
else: else:
@ -87,16 +89,16 @@ class Admin(commands.Cog):
except ConnectionRefusedError: except ConnectionRefusedError:
await log(ctx, "Setup query failed, server down?") await log(ctx, "Setup query failed, server down?")
else: 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, conn, names)
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()
if annChanID is None: if annChanID is None:
await setAnn(ctx, False) 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.command(brief="Turns on total player hour display", description="Turns on total player hour display.")
@commands.has_permissions(administrator=True) @commands.has_permissions(administrator=True)
async def showhours(self, ctx: discord.ext.commands.context.Context): 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.command(brief="Turns off total player hour display", description="Turns off total player hour display.")
@commands.has_permissions(administrator=True) @commands.has_permissions(administrator=True)
async def nohours(self, ctx: discord.ext.commands.context.Context): async def nohours(self, ctx: discord.ext.commands.context.Context):
await setHours(ctx, False) await setShowHours(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)
class Other(commands.Cog): class Other(commands.Cog):
@ -167,33 +147,29 @@ class Other(commands.Cog):
@commands.command(brief="Shows server status", description="Shows server status.") @commands.command(brief="Shows server status", description="Shows server status.")
async def status(self, ctx: discord.ext.commands.context.Context): async def status(self, ctx: discord.ext.commands.context.Context):
mydb, cursor = connect() with sqlite_conn() as conn:
ip, port = getMCIP(ctx.guild.id, cursor) ip, port = getMCIP(ctx.guild.id, conn)
mc = JavaServer(ip, port) 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="```")
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.") @commands.command(brief="Lists online players", description="Lists online players.")
async def players(self, ctx: discord.ext.commands.context.Context): async def players(self, ctx: discord.ext.commands.context.Context):
mydb, cursor = connect() with sqlite_conn() as conn:
ip, port = getMCIP(ctx.guild.id, cursor) ip, port = getMCIP(ctx.guild.id, conn)
mc = JavaServer(ip, port) mc = JavaServer(ip, port)
mydb.close()
if mc is None: if mc is None:
await safe_send("There is no server query set up. Run the `setup` command to get started.", ctx=ctx) 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.") @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): async def lastquery(self, ctx: discord.ext.commands.context.Context):
mydb, cursor = connect() with sqlite_conn() as conn:
ip, port = getMCIP(ctx.guild.id, cursor) ip, port = getMCIP(ctx.guild.id, conn)
mc = JavaServer(ip, port) mc = JavaServer(ip, port)
last = getMCQueryTime(ctx.guild.id, cursor) last = getMCQueryTime(ctx.guild.id, conn)
mydb.close()
if mc is None: if mc is None:
await safe_send("There is no server query set up. Run the `setup` command to get started.", ctx=ctx) 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.") await log(ctx, "Channel", str(cid), "does not exist.")
return return
mydb, cursor = connect() with sqlite_conn() as conn:
ip, _ = getMCIP(ctx.guild.id, cursor) ip, _ = getMCIP(ctx.guild.id, conn)
cursor.execute( conn.execute("""
"UPDATE servers SET announce_joins=" + str((0, 1)[ann]) + ", announce_joins_id=" + ("NULL", str(cid))[ UPDATE servers
ann] + " WHERE id=" + str(ctx.guild.id)) SET
announce_joins = ?,
mydb.commit() announce_joins_id = ?
mydb.close() WHERE id = ?
""", (
ann,
cid if ann else None,
ctx.guild.id
))
await log(ctx, ( await log(ctx, (
"Not announcing when a player joins " + ip + ".", "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]) ann])
async def setHours(ctx: discord.ext.commands.context.Context, hours: bool): async def setShowHours(ctx: discord.ext.commands.context.Context, show_hours: bool):
mydb, cursor = connect() with sqlite_conn() as conn:
ip, _ = getMCIP(ctx.guild.id, cursor) ip, _ = getMCIP(ctx.guild.id, conn)
cursor.execute( conn.execute("""
f"UPDATE servers SET hours={str((0, 1)[hours])} WHERE id={str(ctx.guild.id)}") UPDATE servers
SET show_hours = ?
mydb.commit() WHERE id = ?
mydb.close() """, (
show_hours,
ctx.guild.id
))
await log(ctx, ( await log(ctx, (
"Not displaying total player hours for " + ip + ".", "Not displaying total player hours for " + ip + ".",
"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): async def log(ctx: commands.Context, *msg: str):
@ -349,77 +332,110 @@ async def getStatus(serv: JavaServer):
return p, m, n, d return p, m, n, d
def connect(): @contextmanager
mydb = sqlite3.connect('/data/mstbot.db') def sqlite_conn():
conn = sqlite3.connect('/data/mstbot.db')
cursor = mydb.cursor() try:
return mydb, cursor # 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): def getMCIP(sid: int, conn: sqlite3.Connection):
cursor.execute("SELECT ip, port FROM servers WHERE id=" + str(sid)) row = conn.execute(
row = cursor.fetchone() "SELECT ip, port FROM servers WHERE id = ?",
(sid,)
).fetchone()
ip = row[0] ip = row[0]
port = row[1] port = row[1]
return ip, port return ip, port
def getMCNames(sid: int, cursor: sqlite3.Cursor): def getMCNames(sid: int, conn: sqlite3.Connection):
cursor.execute("SELECT name FROM names WHERE id=" + str(sid)) rows = conn.execute(
rows = cursor.fetchall() "SELECT name FROM names WHERE id = ?",
(sid,)
).fetchall()
return [row[0] for row in rows] return [row[0] for row in rows]
def getMCQueryTime(sid: int, cursor: sqlite3.Cursor): def getMCQueryTime(sid: int, conn: sqlite3.Connection):
cursor.execute("SELECT last_query FROM servers WHERE id=" + str(sid)) tstr = conn.execute(
tstr = cursor.fetchone()[0] "SELECT last_query FROM servers WHERE id = ?",
(sid,)
).fetchone()[0]
if tstr is None: if tstr is None:
return tstr return tstr
return datetime.strptime(tstr, '%Y-%m-%d %H:%M:%S') return datetime.strptime(tstr, '%Y-%m-%d %H:%M:%S')
def getPersonSeconds(sid: int, cursor: sqlite3.Cursor): def getPersonSeconds(sid: int, conn: sqlite3.Connection):
cursor.execute("SELECT time FROM times WHERE id=" + str(sid)) cols = conn.execute(
tstr = cursor.fetchone()[0] 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): def getShowHours(sid: int, conn: sqlite3.Connection):
cursor.execute("SELECT hours FROM servers WHERE id=" + str(sid)) show_hours = conn.execute(
tstr = cursor.fetchone()[0] "SELECT show_hours FROM servers WHERE id = ?",
(sid,)
).fetchone()[0]
return bool(tstr) return show_hours
def getMCJoinAnnounce(sid: int, cursor: sqlite3.Cursor): def getMCJoinAnnounce(sid: int, conn: sqlite3.Connection):
cursor.execute("SELECT announce_joins, announce_joins_id FROM servers WHERE id=" + str(sid)) row = conn.execute(
row = cursor.fetchone() "SELECT announce_joins, announce_joins_id FROM servers WHERE id = ?",
(sid,)
).fetchone()
ann = row[0] ann = row[0]
cid = row[1] cid = row[1]
return ann, cid return ann, cid
def setMCNames(sid: int, cursor: sqlite3.Cursor, names: List[str]): def setMCNames(sid: int, conn: sqlite3.Connection, names: List[str]):
cursor.execute("DELETE FROM names WHERE id=" + str(sid)) conn.execute("DELETE FROM names WHERE id = ?", (sid,))
if len(names) > 0: if names:
qStr = "" rows = [(sid, name) for name in names]
for name in names: conn.executemany("INSERT INTO names (id, name) VALUES (?, ?)", rows)
qStr += "(" + str(sid) + ",\"" + name + "\"),"
qStr = qStr[:-1] + ";" def setMCQueryTime(sid: int, conn: sqlite3.Connection, dt: datetime):
conn.execute("""
cursor.execute("INSERT INTO names (id, name) VALUES " + qStr) 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): def incrementPersonSeconds(sid: int, user: str, conn: sqlite3.Connection, seconds: float):
cursor.execute("UPDATE servers SET last_query=\"" + dt.strftime('%Y-%m-%d %H:%M:%S') + "\" WHERE id=" + str(sid)) conn.execute("""
INSERT INTO times (id, name, seconds)
def incrementPersonSeconds(sid: int, cursor: sqlite3.Cursor, seconds: int): VALUES (?, ?, ?)
cursor.execute(f"UPDATE times SET time=time+{seconds} WHERE id={str(sid)};") 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): async def do_bot_cleanup(sid: int, ctx: Union[discord.ext.commands.context.Context, None] = None):
if sid in servers: 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: except discord.errors.Forbidden:
print(currServ.name, "Error: I don't have permission to delete channels.") print(currServ.name, "Error: I don't have permission to delete channels.")
mydb, cursor = connect() with sqlite_conn() as conn:
ip, port = getMCIP(sid, cursor) ip, port = getMCIP(sid, conn)
mc = JavaServer(ip, port) mc = JavaServer(ip, port)
cursor.execute("DELETE FROM servers WHERE id=" + str(sid)) conn.execute("DELETE FROM servers WHERE id = ?", (sid,))
cursor.execute("DELETE FROM names WHERE id=" + str(sid)) conn.execute("DELETE FROM names WHERE id = ?", (sid,))
cursor.execute("DELETE FROM times WHERE id=" + str(sid)) conn.execute("DELETE FROM times WHERE id = ?", (sid,))
mydb.commit()
mydb.close()
if ctx is None: if ctx is None:
print("Cleaned up", sid, ".") 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.") print(get_server_by_id(sid).name, "is not querying. Ending task.")
return return
mydb, cursor = connect() with sqlite_conn() as conn:
ip, port = getMCIP(sid, cursor) ip, port = getMCIP(sid, conn)
mc = JavaServer(ip, port) mc = JavaServer(ip, port)
currServ = get_server_by_id(sid) currServ = get_server_by_id(sid)
wait = 10 wait = 10
if not ip == "" and currServ is not None: if not ip == "" and currServ is not None:
try: try:
oldNames = getMCNames(sid, cursor) oldNames = getMCNames(sid, conn)
players, max, names, _ = await getStatus(mc) players, max, names, _ = await getStatus(mc)
lastTime = getMCQueryTime(sid, cursor) lastTime = getMCQueryTime(sid, conn)
lastSeconds = getPersonSeconds(sid, cursor) lastSeconds = getPersonSeconds(sid, conn)
currTime = datetime.now(timezone.utc) currTime = datetime.now(timezone.utc)
if lastTime is None: if lastTime is None:
lastTime = currTime lastTime = currTime
else: else:
lastTime = lastTime.replace(tzinfo=timezone.utc) 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))
setMCNames(sid, cursor, names) deltaSeconds = (currTime - lastTime).total_seconds()
setMCQueryTime(sid, cursor, currTime)
if not first_iter: print(currServ.name, "Query:", ip, str(players) + "/" + str(max), datetime.now(timezone.utc).strftime("%H:%M:%S"),
incrementPersonSeconds(sid, cursor, len(names) * (currTime - lastTime).total_seconds()) str(deltaSeconds))
announceJoin, annChanId = getMCJoinAnnounce(sid, cursor) setMCNames(sid, conn, names)
annRole = None setMCQueryTime(sid, conn, currTime)
if not first_iter:
for name in names:
incrementPersonSeconds(sid, name, conn, deltaSeconds)
if announceJoin and annChanId is not None: announceJoin, annChanId = getMCJoinAnnounce(sid, conn)
jNames = list(set(names) - set(oldNames)) annRole = None
for name in jNames:
aChannels = find_channels(serv=currServ, chanid=int(annChanId))
if len(aChannels) > 0: if announceJoin and annChanId is not None:
if annRole is None: jNames = list(set(names) - set(oldNames))
await safe_send(name + " joined the game!", chan=aChannels[0]) for name in jNames:
else: aChannels = find_channels(serv=currServ, chanid=int(annChanId))
await safe_send("<@&" + str(annRole.id) + "> " + name + " joined the game!",
chan=aChannels[0])
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, "Announced player(s) join.")
print(currServ.name, "Timeout, server lagging?")
players = -1
lastSeconds = -1
except (ConnectionRefusedError, socket.gaierror): except asyncio.exceptions.TimeoutError:
print(currServ.name, "Cannot connect to server, down?") print(currServ.name, "Timeout, server lagging?")
players = -1 players = -1
lastSeconds = -1 lastSeconds = -1
iChannels = find_channels(serv=currServ, channame="IP: ", channamesearch="in", chantype=discord.ChannelType.voice) except (ConnectionRefusedError, socket.gaierror):
pChannels = find_channels(serv=currServ, channame="Players: ", channamesearch="in", print(currServ.name, "Cannot connect to server, down?")
chantype=discord.ChannelType.voice) players = -1
tChannels = find_channels(serv=currServ, channame="Player Hrs: ", channamesearch="in", lastSeconds = -1
chantype=discord.ChannelType.voice)
overwrites = { iChannels = find_channels(serv=currServ, channame="IP: ", channamesearch="in", chantype=discord.ChannelType.voice)
currServ.default_role: discord.PermissionOverwrite(connect=False, view_channel=True), pChannels = find_channels(serv=currServ, channame="Players: ", channamesearch="in",
currServ.me: discord.PermissionOverwrite(connect=True, view_channel=True, manage_channels=True) chantype=discord.ChannelType.voice)
} tChannels = find_channels(serv=currServ, channame="Player Hrs: ", channamesearch="in",
chantype=discord.ChannelType.voice)
if len(iChannels) > 0: overwrites = {
lastIPName = iChannels[0].name 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 len(iChannels) > 0:
if lastIPName != ipStr: lastIPName = iChannels[0].name
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(pChannels) > 0: ipStr = "IP: " + ip
lastPName = pChannels[0].name if lastIPName != ipStr:
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:
try: try:
print(currServ.name, "Update: Time changed!") print(currServ.name, "Update: Ip changed!")
await tChannels[0].edit(name=tStr) await iChannels[0].edit(name=ipStr)
wait = 301 wait = 301
except discord.errors.Forbidden: except discord.errors.Forbidden:
print(currServ.name, print(currServ.name,
@ -617,15 +592,53 @@ async def status_task(sid: int):
await do_bot_cleanup(sid) await do_bot_cleanup(sid)
return return
else: else:
await currServ.create_voice_channel(tStr, await currServ.create_voice_channel("IP: " + ip, overwrites=overwrites)
overwrites=overwrites)
elif not do_show_hours:
if len(tChannels) > 0:
for channel in tChannels:
await channel.delete()
mydb.commit() if len(pChannels) > 0:
mydb.close() 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) await asyncio.sleep(wait)
first_iter = False first_iter = False

View file

@ -1,3 +1,4 @@
PRAGMA journal_mode = WAL;
CREATE TABLE names (id INTEGER NOT NULL, name TEXT NOT NULL, UNIQUE (id, name)); 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 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, hours REAL NOT NULL DEFAULT 0, announce_joins BOOLEAN NOT NULL DEFAULT FALSE, announce_joins_id INTEGER) WITHOUT ROWID; 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;