From 0747facaad734a884d9b0b7a745fd77d3fd63195 Mon Sep 17 00:00:00 2001 From: "d.shuvalov" <46745805+PrEvIeS@users.noreply.github.com> Date: Tue, 5 May 2026 17:36:05 +0300 Subject: [PATCH] Show [AFK] suffix and afk small-image while AFK/DND is on MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Detect `: AFK mode is now ON. Autoreply "..."` and `: AFK mode is now OFF` (also DND variants) from Client.txt and reflect that state in Discord Rich Presence. - AFK ON: append "[AFK]" to the state string and replace the small_image with "afk". The previous small_image (derived from the player's class / ascendency) is snapshotted so AFK OFF can restore EXACTLY this value even if a level-up happened during the AFK window. - AFK OFF: restore the snapshotted small_image; clear the snapshot. `update_rpc()` gains two optional kwargs (`small_image_override`, `afk_suffix`) that default to the pre-existing behaviour, so all current call sites stay byte-identical. Implementation is fully gated behind the new `regex_afk` match — non-AFK lines hit zero new code paths. Note: requires uploading an `afk.png` asset to the Discord developer portal under the application's Rich Presence assets (see README). --- main.py | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/main.py b/main.py index 7ee959b..82ef4de 100644 --- a/main.py +++ b/main.py @@ -243,13 +243,22 @@ def rpc_connect(): return None -def update_rpc(level_info, instance_info=None, status=None): +def update_rpc( + level_info, + instance_info=None, + status=None, + small_image_override=None, + afk_suffix=False, +): if instance_info: status = f"In: {instance_info['location_name']} (Lvl {instance_info['location_level']})" else: if status is None: status = random_status() + if afk_suffix: + status = f"{status} [AFK]" + try: details = ( f"{level_info['username']} ({level_info['base_class']}" @@ -260,11 +269,15 @@ def update_rpc(level_info, instance_info=None, status=None): ) + f" - Lvl {level_info['level']})" ) + if small_image_override is not None: + small_image = small_image_override + else: + small_image = level_info["ascension_class"].lower().replace(" ", "_") rpc.update( details=details, state=status, start=int(datetime.datetime.now().timestamp()), - small_image=level_info["ascension_class"].lower().replace(" ", "_"), + small_image=small_image, ) except Exception as e: logging.error(f"Failed to update RPC: {e}") @@ -272,6 +285,10 @@ def update_rpc(level_info, instance_info=None, status=None): regex_level = re.compile(r": (\w+) \(([\w\s]+)\) is now level (\d+)") regex_instance = re.compile(r'Generating level (\d+) area "([^"]+)" with seed (\d+)') +regex_afk = re.compile(r': (DND|AFK) mode is now (?:(ON)\. Autoreply "(.*)"|(OFF))') + +_afk_on = False +_prior_small_image: Optional[str] = None def monitor_log(): @@ -298,6 +315,8 @@ def monitor_log(): small_image=last_level_info["ascension_class"].lower(), ) + global _afk_on, _prior_small_image + with log_file_path.open("r", encoding="utf-8") as log_file: log_file.seek(0, 2) @@ -322,6 +341,33 @@ def monitor_log(): current_status["instance_info"] = instance_info update_rpc(current_status["level_info"], instance_info) + afk_match = regex_afk.search(line) + if afk_match and current_status["level_info"]: + on_token = afk_match.group(2) + if on_token == "ON": + # Snapshot current small_image so OFF restores EXACTLY + # this value, even if level changes during AFK window. + _prior_small_image = ( + current_status["level_info"]["ascension_class"] + .lower() + .replace(" ", "_") + ) + _afk_on = True + update_rpc( + current_status["level_info"], + current_status["instance_info"], + small_image_override="afk", + afk_suffix=True, + ) + else: + _afk_on = False + update_rpc( + current_status["level_info"], + current_status["instance_info"], + small_image_override=_prior_small_image, + ) + _prior_small_image = None + time.sleep(5)