From cb10d3228f8bb8e11a4db37b30776afe6e350ae2 Mon Sep 17 00:00:00 2001 From: whysooraj Date: Sun, 29 Mar 2026 11:27:30 +0530 Subject: [PATCH 1/2] Fix recursive installation and add Wayland/Hyprland support This commit: - Removes the recursive git clone in install script - Fixes directory nesting in install/update - Adds Hyprland support for window tracking - Handles xprintidle failures on Wayland - Uses pactl for video playback detection --- install | 6 +++--- src/Watcher/afk.py | 13 ++++++++++--- src/Watcher/get_windows.py | 29 +++++++++++++++++++++++------ update | 3 ++- 4 files changed, 38 insertions(+), 13 deletions(-) diff --git a/install b/install index 310071d..e9400cc 100755 --- a/install +++ b/install @@ -1,5 +1,4 @@ #!/bin/bash -git clone https://github.com/Waishnav/Watcher -b v2.0 && cd Watcher && ./install echo "[✔] First of all Thanks for dropping by!." sleep 1s @@ -9,9 +8,10 @@ echo "[✔] Also some of the features are in development AFK is one of them" sleep 2s echo "[✔] So let's start installation process... " -sudo cp -r ./src/Watcher /usr/share/ +sudo mkdir -p /usr/share/Watcher/ +sudo cp -r ./src/Watcher/* /usr/share/Watcher/ echo "[✔] Copying Watcher to /usr/share/" -sudo cp -r ./src/bin/watcher /usr/local/bin/ +sudo cp ./src/bin/watcher /usr/local/bin/ echo "[✔] Copying watcher executable to /usr/local/bin/" sudo chmod +x /usr/local/bin/watcher echo "[✔] Making it executable by giving it permission" diff --git a/src/Watcher/afk.py b/src/Watcher/afk.py index 3d92068..8d98a58 100755 --- a/src/Watcher/afk.py +++ b/src/Watcher/afk.py @@ -17,11 +17,18 @@ def returned_from_afk(afk_active, timeout): def is_afk(timeout): timeout = timeout * 60 * 1000 - 100 # minimizing 100 milisec error #If the AFK feature is installed - time_since_last_input = int(os.popen("xprintidle").read()[:-1]) + try: + idle_output = os.popen("xprintidle").read()[:-1] + if not idle_output or "extension not supported" in idle_output: + return False + time_since_last_input = int(idle_output) + except: + return False + if (time_since_last_input > timeout): - video_playback = os.popen("""pacmd list-sink-inputs | grep -w state | grep -i 'RUNNING'""").read() + video_playback = os.popen("""pactl list sink-inputs 2>/dev/null | grep -i 'Corked: no'""").read() # if playback is not running as well as user is AFK - if "RUNNING" in video_playback: + if "Corked: no" in video_playback: return False # if playback is running is background as well as user is AFK else: diff --git a/src/Watcher/get_windows.py b/src/Watcher/get_windows.py index a0be469..66e1a3d 100755 --- a/src/Watcher/get_windows.py +++ b/src/Watcher/get_windows.py @@ -1,7 +1,16 @@ import os +import json # get title name of app that user working on def active_window_title(): + if os.environ.get("XDG_CURRENT_DESKTOP") == "Hyprland": + try: + output = os.popen("hyprctl activewindow -j").read() + data = json.loads(output) + return data.get("title", "") + except: + return "" + active_window_title = os.popen('''xprop -id $(xdotool getwindowfocus) WM_NAME''').read()[19:-2] a = active_window_title.find('"') active_window_title = active_window_title[a+1:] @@ -13,13 +22,21 @@ def active_window_title(): # get classname of app that user working on def active_window(): - actv_id = os.popen("xdotool getwindowfocus").read()[:-1] - if len(actv_id) == 4: - active_window = "" + if os.environ.get("XDG_CURRENT_DESKTOP") == "Hyprland": + try: + output = os.popen("hyprctl activewindow -j").read() + data = json.loads(output) + active_window = data.get("initialClass", data.get("class", "")) + except: + active_window = "" else: - active_window = os.popen("xprop -id $(xdotool getwindowfocus) | grep CLASS ").read() - if active_window != "": - active_window = active_window[19:-1].replace('''"''', "").split(", ")[1] + actv_id = os.popen("xdotool getwindowfocus").read()[:-1] + if len(actv_id) == 4 or "failed" in actv_id: + active_window = "" + else: + active_window = os.popen("xprop -id $(xdotool getwindowfocus) | grep CLASS ").read() + if active_window != "": + active_window = active_window[19:-1].replace('''"''', "").split(", ")[1] if "XGetWindowProperty[_NET_ACTIVE_WINDOW] failed" in active_window: active_window = "" diff --git a/update b/update index d932630..3dbd7f6 100755 --- a/update +++ b/update @@ -1,7 +1,8 @@ #!/bin/bash +sudo mkdir -p /usr/share/Watcher/ sudo rm -rf /usr/share/Watcher/* sudo cp -r ./src/Watcher/* /usr/share/Watcher/ -sudo cp -r ./src/bin/watcher /usr/local/bin/ +sudo cp ./src/bin/watcher /usr/local/bin/ sudo chmod +x /usr/local/bin/watcher echo "[✔] Updating Finished." From 746d05d19fc100a2d8567b7e05891c4885afd972 Mon Sep 17 00:00:00 2001 From: whysooraj Date: Sun, 29 Mar 2026 11:34:46 +0530 Subject: [PATCH 2/2] Silence noisy output and remove debug prints --- src/Watcher/afk.py | 2 +- src/Watcher/watch_log.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Watcher/afk.py b/src/Watcher/afk.py index 8d98a58..c8cfb74 100755 --- a/src/Watcher/afk.py +++ b/src/Watcher/afk.py @@ -18,7 +18,7 @@ def is_afk(timeout): timeout = timeout * 60 * 1000 - 100 # minimizing 100 milisec error #If the AFK feature is installed try: - idle_output = os.popen("xprintidle").read()[:-1] + idle_output = os.popen("xprintidle 2>/dev/null").read()[:-1] if not idle_output or "extension not supported" in idle_output: return False time_since_last_input = int(idle_output) diff --git a/src/Watcher/watch_log.py b/src/Watcher/watch_log.py index 6a44ca5..c23c10d 100755 --- a/src/Watcher/watch_log.py +++ b/src/Watcher/watch_log.py @@ -56,8 +56,7 @@ def log_creation(): date = get_date() filename = "/home/"+os.getlogin()+"/.cache/Watcher/daily_data/"+date+".csv" afk = y.is_afk(afkTimeout) - print(data) - + if not(afk): active_window = x.active_window() usage = data.get(active_window)