diff --git a/config.py b/config.py new file mode 100644 index 0000000..b3e2e63 --- /dev/null +++ b/config.py @@ -0,0 +1,24 @@ +import json +from typing import List +from pydantic import BaseModel + + +class BlockList(BaseModel): + name: str = '' + prefix: str = '' + postfix: str = '' + items: List[str] + + +class Config(BaseModel): + class Config: + extra = 'forbid' + + blocklists: List[BlockList] + + +def load_config(config_file: str) -> Config: + with open(config_file, 'r', encoding='utf8') as f: + config_dict = json.load(f) + return Config(**config_dict) + diff --git a/focusfriend.code-workspace b/focusfriend.code-workspace new file mode 100644 index 0000000..ab68550 --- /dev/null +++ b/focusfriend.code-workspace @@ -0,0 +1,31 @@ +{ + "python.linting.pylintEnabled": false, + "python.linting.enabled": false, + "folders": [ + { + "path": "." + } + ], + "launch": { + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Current File", + "type": "python", + "request": "launch", + "program": "${file}", + "console": "integratedTerminal" + }, + { + "name": "FocusFriend Debug", + "type": "python", + "request": "launch", + "program": "focusfriend.py", + "console": "integratedTerminal", + "args": [ + "--debug", + ], + } + ] + } +} \ No newline at end of file diff --git a/focusfriend.py b/focusfriend.py index 34d821e..9ddf9db 100755 --- a/focusfriend.py +++ b/focusfriend.py @@ -1,14 +1,17 @@ #!/usr/bin/env python3 import os -import psutil import re import subprocess import sys import time from typing import List, Tuple, Set +import psutil +import config + FOCUSFRIEND_PY = "focusfriend.py" +CONFIG_FILE = "config.json" BLOCKER_CONFIG_DIR = "/home/{}/.config/focusfriend" BLOCKED_BROWSER_WORDS_TXT = "blocked_browser_words.txt" WINDOW_NAMES_TXT = "window_names.txt" @@ -22,10 +25,8 @@ def is_window_blocked(window_name: str, blocked: List[re.Pattern]) -> bool: def get_active_window_name_and_pid() -> Tuple[str, str]: - CMD = ["xdotool", "getactivewindow", "getwindowname", "getwindowpid"] - p = subprocess.run(CMD, capture_output=True) - if p.returncode != 0: - return ("", "") + cmd = ["xdotool", "getactivewindow", "getwindowname", "getwindowpid"] + p = subprocess.run(cmd, capture_output=True, check=True) window_name, window_pid, _ = p.stdout.decode().split("\n") return (window_name, window_pid) @@ -48,17 +49,22 @@ def kill_sequence(blocked: List[re.Pattern]) -> None: def notify(message: str) -> None: + """Notify user via the Xorg notify-send command. + + Args: + message (str): Message shown to the user. + """ 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) + cmd = ["runuser", "-m", "-u", user, "notify-send", message] + subprocess.run(cmd, env=env) def get_config_dir() -> str: - user = os.environ["SUDO_USER"] + user = os.environ.get("SUDO_USER", False) or os.environ["USER"] config_dir = BLOCKER_CONFIG_DIR.format(user) assert(os.path.isdir(config_dir)) return config_dir @@ -117,14 +123,20 @@ def load_window_names() -> Set[str]: def write_window_names(window_names: Set[str]) -> None: config_dir = get_config_dir() - window_names = sorted(list(window_names)) - window_names = "\n".join(window_names) window_names_file = os.path.join(config_dir, WINDOW_NAMES_TXT) + window_names = "\n".join(sorted(list(window_names))) with open(window_names_file, "w") as f: - f.write(window_names_file) + f.write(window_names) + + +def load_config() -> config.Config: + config_dir = get_config_dir() + config_file = os.path.join(config_dir, CONFIG_FILE) + config_obj = config.load_config(config_file) def main() -> None: + # config = load_config() init() blocked = load_blocked_browser_words() window_names = load_window_names() @@ -140,7 +152,17 @@ def main() -> None: counter += 1 -if __name__ == "__main__": +def sudo_run() -> None: + """Run main as root except while debugging. + """ + try: + if sys.argv[1] == "--debug": + terminate_existing_blocker() + main() + return + except IndexError: + pass + if os.geteuid() == 0: newpid = os.fork() if newpid == 0: @@ -148,3 +170,7 @@ if __name__ == "__main__": else: cmd = ["sudo", FOCUSFRIEND_PY] + sys.argv[1:] subprocess.Popen(cmd) + + +if __name__ == "__main__": + sudo_run() diff --git a/hash.py b/hash.py deleted file mode 100755 index 7978b1b..0000000 --- a/hash.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python3 - -import hashlib -import sys -import time -import getpass - - -def get_input(): - total_count = 0 - while not total_count: - try: - total_count = int(float(input("Enter count: "))) - except ValueError: - print("Enter a positive integer.") - - seed, seed_check = "a", "b" - while seed != seed_check: - seed = getpass.getpass() - seed_check = getpass.getpass(prompt="Confirm password: ") - if seed != seed_check: - print("Passwords must match.") - return total_count, seed - - -def print_progress(total_count, passed_time, current_count): - projected_time = total_count * passed_time / current_count - progress_time = "[{:.2f} / {:.2f}s".format(passed_time, projected_time) - progress_percent = current_count / total_count * 100 - progress_percent = "- {:.2f}%]".format(progress_percent) - print(progress_time, progress_percent, " ", end='\r') - - -if __name__ == "__main__": - total_count, seed = get_input() - - start_time = time.time() - current_time = start_time - m = hashlib.sha256() - m.update(seed.encode()) - - for current_count in range(total_count): - if time.time() - current_time > 1: - current_time = time.time() - passed_time = current_time - start_time - print_progress(total_count, passed_time, current_count) - m.update(m.digest()) - - print("{} hashes done. Final result:".format(total_count)) - print(m.hexdigest()) -