Files
antidrift/blocker.py

122 lines
3.2 KiB
Python
Executable File

#!/usr/bin/env python3
import os
import psutil
import re
import subprocess
import sys
import time
BLOCKER = "blocker.py"
BLOCKER_CONFIG_DIR = "/home/{}/.config/focusfriend"
BLOCKED_BROWSER_WORDS = ["mogelpower", "DER SPIEGEL", "nitter"]
def is_window_blocked(window_name, blocked):
for b in blocked:
if type(b) is str and b == window_name:
return True
elif type(b) is re.Pattern and b.findall(window_name):
return True
return False
def get_active_window_name_and_pid():
CMD = ["xdotool", "getactivewindow", "getwindowname", "getwindowpid"]
p = subprocess.run(CMD, capture_output=True)
if p.returncode != 0:
return "", ""
window_name, window_pid, _ = p.stdout.decode().split("\n")
return window_name, window_pid
def find_window_name(window_name):
CMD = ["xdotool", "search", window_name, "getwindowpid"]
p = subprocess.run(CMD, capture_output=True)
if p.returncode != 0:
return ""
l = p.stdout.decode().split("\n")
def init_kill_sequence(blocked):
count = 5
while True:
window_name, window_pid = get_active_window_name_and_pid()
if not is_window_blocked(window_name, blocked):
notify(f"{window_name} is okay. Return from kill sequence.")
return
notify(f"{window_name} is blocked. Kill in {count} seconds.")
if count == 0:
p = psutil.Process(int(window_pid))
p.kill()
return
time.sleep(1)
count -= 1
def notify(message):
env = {
**os.environ,
"DBUS_SESSION_BUS_ADDRESS": "unix:path=/run/user/1000/bus"
}
user = env["SUDO_USER"]
CMD = ["runuser", "-m", "-u", user, "notify-send", message]
p = subprocess.run(CMD, env=env)
def get_config_dir() -> str:
user = os.environ["SUDO_USER"]
config_dir = BLOCKER_CONFIG_DIR.format(user)
assert(os.path.isdir(config_dir))
return config_dir
def write_pid_file() -> str:
p = psutil.Process()
pid_file = os.path.join(get_config_dir(), f"{p.pid}.pid")
with open(pid_file, "w") as f:
f.write(pid_file)
return pid_file
def terminate_existing_blocker() -> None:
this_pid = psutil.Process().pid
config_dir = get_config_dir()
pid_files = [f for f in os.listdir(config_dir) if f.endswith(".pid")]
for pid_file in pid_files:
pid = int(pid_file.replace(".pid", ""))
if this_pid == pid:
continue
try:
p = psutil.Process(pid)
p.terminate()
except psutil.NoSuchProcess:
pass
os.remove(os.path.join(config_dir, pid_file))
def init() -> None:
terminate_existing_blocker()
write_pid_file()
def main() -> None:
init()
blocked = [re.compile(f"{word}.*(Firefox|Chromium)", flags=re.IGNORECASE)
for word in BLOCKED_BROWSER_WORDS]
while True:
time.sleep(1)
window_name, window_pid = get_active_window_name_and_pid()
if is_window_blocked(window_name, blocked):
init_kill_sequence(blocked)
if __name__ == "__main__":
if os.geteuid() == 0:
newpid = os.fork()
if newpid == 0:
main()
else:
cmd = ["sudo", BLOCKER] + sys.argv[1:]
subprocess.Popen(cmd)