Track Last Cleanup time
This commit is contained in:
18
README.md
18
README.md
@@ -38,16 +38,16 @@ Fill out values in the .env and you're good to go!
|
|||||||

|

|
||||||
|
|
||||||
***User Commands***
|
***User Commands***
|
||||||
- !createaccount <username> <password> - Create your Jellyfin account
|
- `!createaccount` <username> <password> - Create your Jellyfin account
|
||||||
- !recoveraccount <username> <newpassword> - Reset your password
|
- `!recoveraccount` <username> <newpassword> - Reset your password
|
||||||
- !deleteaccount <username> - Delete your Jellyfin account
|
- `!deleteaccount` <username> - Delete your Jellyfin account
|
||||||
|
|
||||||
***Admin Commands***
|
***Admin Commands***
|
||||||
- !syncaccounts - Remove Jellyfin accounts from users without roles
|
- `!cleanup` - Remove Jellyfin accounts from users without roles
|
||||||
- !searchaccount <jellyfin_username> - Find linked Discord user
|
- `!searchaccount` <jellyfin_username> - Find linked Discord user
|
||||||
- !searchdiscord @user - Find linked Jellyfin account
|
- `!searchdiscord` @user - Find linked Jellyfin account
|
||||||
- !scanlibraries - Scan all Jellyfin libraries
|
- `!scanlibraries` - Scan all Jellyfin libraries
|
||||||
- !assignaccount <jellyfin_username> @user - Manually link accounts
|
- `!assignaccount` <jellyfin_username> @user - Manually link accounts
|
||||||
|
|
||||||
***Admin Bot Commands***
|
***Admin Bot Commands***
|
||||||
- !setprefix - Change the bots command prefix
|
- `!setprefix` - Change the bots command prefix
|
||||||
86
app.py
86
app.py
@@ -47,6 +47,7 @@ bot = commands.Bot(command_prefix=PREFIX, intents=intents, help_command=None)
|
|||||||
# DATABASE SETUP
|
# DATABASE SETUP
|
||||||
# =====================
|
# =====================
|
||||||
def init_db():
|
def init_db():
|
||||||
|
# Existing DB creation
|
||||||
conn = mysql.connector.connect(
|
conn = mysql.connector.connect(
|
||||||
host=DB_HOST, user=DB_USER, password=DB_PASSWORD
|
host=DB_HOST, user=DB_USER, password=DB_PASSWORD
|
||||||
)
|
)
|
||||||
@@ -66,6 +67,13 @@ def init_db():
|
|||||||
jellyfin_username VARCHAR(255) NOT NULL
|
jellyfin_username VARCHAR(255) NOT NULL
|
||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
|
# New table for metadata
|
||||||
|
cur.execute("""
|
||||||
|
CREATE TABLE IF NOT EXISTS bot_metadata (
|
||||||
|
key_name VARCHAR(255) PRIMARY KEY,
|
||||||
|
value VARCHAR(255) NOT NULL
|
||||||
|
)
|
||||||
|
""")
|
||||||
conn.commit()
|
conn.commit()
|
||||||
cur.close()
|
cur.close()
|
||||||
conn.close()
|
conn.close()
|
||||||
@@ -168,6 +176,33 @@ def has_required_role(member):
|
|||||||
def has_admin_role(member):
|
def has_admin_role(member):
|
||||||
return any(role.id in ADMIN_ROLE_IDS for role in member.roles)
|
return any(role.id in ADMIN_ROLE_IDS for role in member.roles)
|
||||||
|
|
||||||
|
# =====================
|
||||||
|
# BOT HELPERS
|
||||||
|
# =====================
|
||||||
|
|
||||||
|
def set_metadata(key, value):
|
||||||
|
conn = mysql.connector.connect(
|
||||||
|
host=DB_HOST, user=DB_USER, password=DB_PASSWORD, database=DB_NAME
|
||||||
|
)
|
||||||
|
cur = conn.cursor()
|
||||||
|
cur.execute("""
|
||||||
|
REPLACE INTO bot_metadata (key_name, value) VALUES (%s, %s)
|
||||||
|
""", (key, str(value)))
|
||||||
|
conn.commit()
|
||||||
|
cur.close()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
def get_metadata(key):
|
||||||
|
conn = mysql.connector.connect(
|
||||||
|
host=DB_HOST, user=DB_USER, password=DB_PASSWORD, database=DB_NAME
|
||||||
|
)
|
||||||
|
cur = conn.cursor()
|
||||||
|
cur.execute("SELECT value FROM bot_metadata WHERE key_name=%s", (key,))
|
||||||
|
row = cur.fetchone()
|
||||||
|
cur.close()
|
||||||
|
conn.close()
|
||||||
|
return row[0] if row else None
|
||||||
|
|
||||||
# =====================
|
# =====================
|
||||||
# EVENTS
|
# EVENTS
|
||||||
# =====================
|
# =====================
|
||||||
@@ -261,7 +296,7 @@ async def deleteaccount(ctx, username: str):
|
|||||||
await ctx.send("❌ Failed to delete account.")
|
await ctx.send("❌ Failed to delete account.")
|
||||||
|
|
||||||
@bot.command()
|
@bot.command()
|
||||||
async def syncaccounts(ctx):
|
async def cleanup(ctx):
|
||||||
guild = bot.get_guild(GUILD_ID)
|
guild = bot.get_guild(GUILD_ID)
|
||||||
removed = []
|
removed = []
|
||||||
for discord_id, jf_username in get_accounts():
|
for discord_id, jf_username in get_accounts():
|
||||||
@@ -275,7 +310,33 @@ async def syncaccounts(ctx):
|
|||||||
if removed and log_channel:
|
if removed and log_channel:
|
||||||
await log_channel.send(f"🧹 Removed {len(removed)} Jellyfin accounts: {', '.join(removed)}")
|
await log_channel.send(f"🧹 Removed {len(removed)} Jellyfin accounts: {', '.join(removed)}")
|
||||||
|
|
||||||
await ctx.send("✅ Sync complete.")
|
await ctx.send("✅ Cleanup complete.")
|
||||||
|
|
||||||
|
@bot.command()
|
||||||
|
async def lastcleanup(ctx):
|
||||||
|
member = ctx.guild.get_member(ctx.author.id)
|
||||||
|
if not has_admin_role(member):
|
||||||
|
await ctx.send("❌ You don’t have permission to view the last cleanup.")
|
||||||
|
return
|
||||||
|
|
||||||
|
last_run = get_metadata("last_cleanup")
|
||||||
|
if not last_run:
|
||||||
|
await ctx.send("ℹ️ No cleanup has been run yet.")
|
||||||
|
return
|
||||||
|
|
||||||
|
last_run_dt = datetime.datetime.fromisoformat(last_run)
|
||||||
|
now = datetime.datetime.utcnow()
|
||||||
|
next_run_dt = last_run_dt + datetime.timedelta(hours=24)
|
||||||
|
time_remaining = next_run_dt - now
|
||||||
|
|
||||||
|
hours, remainder = divmod(int(time_remaining.total_seconds()), 3600)
|
||||||
|
minutes, seconds = divmod(remainder, 60)
|
||||||
|
|
||||||
|
await ctx.send(
|
||||||
|
f"🧹 Last cleanup ran at **{last_run_dt.strftime('%Y-%m-%d %H:%M:%S')} UTC**\n"
|
||||||
|
f"⏳ Time until next cleanup: {hours}h {minutes}m {seconds}s"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@bot.command()
|
@bot.command()
|
||||||
async def searchaccount(ctx, username: str):
|
async def searchaccount(ctx, username: str):
|
||||||
@@ -374,7 +435,7 @@ async def help_command(ctx):
|
|||||||
|
|
||||||
if is_admin:
|
if is_admin:
|
||||||
embed.add_field(name="Admin Commands", value=(
|
embed.add_field(name="Admin Commands", value=(
|
||||||
f"`{PREFIX}syncaccounts` - Remove Jellyfin accounts from users without roles\n"
|
f"`{PREFIX}cleanup` - Remove Jellyfin accounts from users without roles\n"
|
||||||
f"`{PREFIX}searchaccount <jellyfin_username>` - Find linked Discord user\n"
|
f"`{PREFIX}searchaccount <jellyfin_username>` - Find linked Discord user\n"
|
||||||
f"`{PREFIX}searchdiscord @user` - Find linked Jellyfin account\n"
|
f"`{PREFIX}searchdiscord @user` - Find linked Jellyfin account\n"
|
||||||
f"`{PREFIX}scanlibraries` - Scan all Jellyfin libraries\n"
|
f"`{PREFIX}scanlibraries` - Scan all Jellyfin libraries\n"
|
||||||
@@ -389,23 +450,42 @@ async def help_command(ctx):
|
|||||||
# =====================
|
# =====================
|
||||||
# TASKS
|
# TASKS
|
||||||
# =====================
|
# =====================
|
||||||
|
import datetime
|
||||||
|
|
||||||
@tasks.loop(hours=24)
|
@tasks.loop(hours=24)
|
||||||
async def daily_check():
|
async def daily_check():
|
||||||
guild = bot.get_guild(GUILD_ID)
|
guild = bot.get_guild(GUILD_ID)
|
||||||
removed = []
|
removed = []
|
||||||
|
|
||||||
for discord_id, jf_username in get_accounts():
|
for discord_id, jf_username in get_accounts():
|
||||||
m = guild.get_member(discord_id)
|
m = guild.get_member(discord_id)
|
||||||
if m is None or not has_required_role(m):
|
if m is None or not has_required_role(m):
|
||||||
if delete_jellyfin_user(jf_username):
|
if delete_jellyfin_user(jf_username):
|
||||||
delete_account(discord_id)
|
delete_account(discord_id)
|
||||||
removed.append(jf_username)
|
removed.append(jf_username)
|
||||||
|
|
||||||
if removed:
|
if removed:
|
||||||
print(f"Daily cleanup: removed {len(removed)} accounts: {removed}")
|
print(f"Daily cleanup: removed {len(removed)} accounts: {removed}")
|
||||||
|
|
||||||
|
# Log last run timestamp
|
||||||
|
set_metadata("last_cleanup", datetime.datetime.utcnow().isoformat())
|
||||||
|
|
||||||
|
|
||||||
@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}")
|
||||||
init_db()
|
init_db()
|
||||||
|
|
||||||
|
# Check last cleanup
|
||||||
|
last_run = get_metadata("last_cleanup")
|
||||||
|
if last_run:
|
||||||
|
last_run_dt = datetime.datetime.fromisoformat(last_run)
|
||||||
|
now = datetime.datetime.utcnow()
|
||||||
|
delta = now - last_run_dt
|
||||||
|
if delta.total_seconds() >= 24 * 3600:
|
||||||
|
print("Running missed daily cleanup...")
|
||||||
|
await daily_check() # Run immediately if overdue
|
||||||
|
|
||||||
daily_check.start()
|
daily_check.start()
|
||||||
await bot.change_presence(activity=discord.Activity(type=discord.ActivityType.watching, name=f"{PREFIX}help"))
|
await bot.change_presence(activity=discord.Activity(type=discord.ActivityType.watching, name=f"{PREFIX}help"))
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user