From 4f036f93a49200648e3af56a3b9b4ed07f6aa15b Mon Sep 17 00:00:00 2001 From: Kyle Saburao <170990857+kylesaburao@users.noreply.github.com> Date: Tue, 14 Apr 2026 20:26:50 -0700 Subject: [PATCH 1/2] single init role object --- src/study_guard.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/study_guard.py b/src/study_guard.py index 63c8d0e..4317ab8 100644 --- a/src/study_guard.py +++ b/src/study_guard.py @@ -121,6 +121,7 @@ def setup(bot: discord.Client, config): join_history: dict[int, list[datetime]] = defaultdict(list) short_stay_history: dict[int, list[datetime]] = defaultdict(list) user_joined_at: dict[int, datetime] = {} + study_time_role = None @tasks.loop(seconds=cleanup_interval_s) @@ -150,6 +151,8 @@ async def cleanup_stale_history(): async def on_ready(bot: discord.Client): + nonlocal study_time_role + if not cleanup_stale_history.is_running(): cleanup_stale_history.start() @@ -199,13 +202,11 @@ async def on_voice_state_update( before: discord.VoiceState, after: discord.VoiceState, ): + if not study_time_role: + raise RuntimeError('Study Time Role is missing. Initialization failed') + await bot.wait_until_ready() - target_role = discord.utils.get(member.guild.roles, name=role_name) - if not target_role: - await send_channel_message(bot, moderation_channel_id, f'[ERROR] Unable to locate role "{role_name}" through member context') - return - now = datetime.now(timezone.utc) new_channel_id = after.channel.id if after.channel else None old_channel_id = before.channel.id if before.channel else None @@ -256,9 +257,9 @@ async def on_voice_state_update( user_joined_at[member.id] = now try: - await member.add_roles(target_role) + await member.add_roles(study_time_role) except Exception as e: - await send_channel_message(bot, moderation_channel_id, f"[ERROR] Failed to add role {target_role.name} to {member.name} ({member.id}): {e}") + await send_channel_message(bot, moderation_channel_id, f"[ERROR] Failed to add role {study_time_role.name} to {member.name} ({member.id}): {e}") elif is_left: # Record short stay if applicable @@ -271,9 +272,9 @@ async def on_voice_state_update( short_stay_history[member.id].append(now) try: - await member.remove_roles(target_role) + await member.remove_roles(study_time_role) except Exception as e: - await send_channel_message(bot, moderation_channel_id, f"[ERROR] Failed to remove role ${target_role.name} from {member.name} ({member.id}): {e}") + await send_channel_message(bot, moderation_channel_id, f"[ERROR] Failed to remove role ${study_time_role.name} from {member.name} ({member.id}): {e}") except Exception as error: await send_channel_message(bot, moderation_channel_id, f"[ERROR] An error occurred while processing role change: {error}") From 3e6acfcbb80c3e2d6a59eeaa1ad7c32d38eabb7f Mon Sep 17 00:00:00 2001 From: Kyle Saburao <170990857+kylesaburao@users.noreply.github.com> Date: Tue, 14 Apr 2026 20:42:43 -0700 Subject: [PATCH 2/2] track timestamp for state update before wait for sync --- src/study_guard.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/study_guard.py b/src/study_guard.py index 4317ab8..81c8277 100644 --- a/src/study_guard.py +++ b/src/study_guard.py @@ -204,10 +204,10 @@ async def on_voice_state_update( ): if not study_time_role: raise RuntimeError('Study Time Role is missing. Initialization failed') - - await bot.wait_until_ready() now = datetime.now(timezone.utc) + await bot.wait_until_ready() + new_channel_id = after.channel.id if after.channel else None old_channel_id = before.channel.id if before.channel else None is_joined = new_channel_id == vc_channel_id and old_channel_id != vc_channel_id