From fd81b57ee2b46545d023999aec131463e854aab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Gaspar?= Date: Sun, 5 Apr 2026 17:52:08 +0100 Subject: [PATCH 1/8] Fix: improve web blocker platform compatibility --- Website Blocker/{read.me => README.md} | 17 ++++--- Website Blocker/cross-platform/web_blocker.py | 45 +++++++++++++++++++ 2 files changed, 56 insertions(+), 6 deletions(-) rename Website Blocker/{read.me => README.md} (51%) create mode 100644 Website Blocker/cross-platform/web_blocker.py diff --git a/Website Blocker/read.me b/Website Blocker/README.md similarity index 51% rename from Website Blocker/read.me rename to Website Blocker/README.md index a782bcc1..cf2197a1 100644 --- a/Website Blocker/read.me +++ b/Website Blocker/README.md @@ -1,12 +1,17 @@ +# Description This is real world program which blocks certain distracting website like Facebook, Youtube etc during your work hours. About the program : What we are going to in this program is that we will pass the link of websites which you think is distracting and the time that you are working on your computer and program will block those website. -Program Architecture: - for mac:- -1. Every system have host file whether it is Mac, Windows or Linux. -Host file in Mac and Linux : "/etc/hosts"\ +>Program Architecture: +Every system have host file whether it is Mac, Windows or Linux. + 1. for mac: Host file in Mac and Linux : "/etc/hosts"\ +2. for windows:- +C:\Windows\System32\drivers\etc\hosts + +## Usage +Insert working hours, and blacklisted websties in the script. The run: + +> python web_blocker.py -for windows:- -C:\Windows\System32\drivers\etc diff --git a/Website Blocker/cross-platform/web_blocker.py b/Website Blocker/cross-platform/web_blocker.py new file mode 100644 index 00000000..33ac918c --- /dev/null +++ b/Website Blocker/cross-platform/web_blocker.py @@ -0,0 +1,45 @@ +import time +import platform +from datetime import datetime as dt + +# Detect OS and set hosts path +if platform.system() == "Windows": + hosts_path = r"C:\Windows\System32\drivers\etc\hosts" +else: + hosts_path = "/etc/hosts" + +redirect = "127.0.0.1" + +website_list = [ + "www.facebook.com", "facebook.com"] + +START_HOUR = 8 +END_HOUR = 16 + +while True: + now = dt.now() + start = dt(now.year, now.month, now.day, START_HOUR) + end = dt(now.year, now.month, now.day, END_HOUR) + + if start < now < end: + print("Working hours...") + + with open(hosts_path, "r+") as file: + content = file.read() + + for website in website_list: + if website not in content: + file.write(f"{redirect} {website}\n") + + else: + with open(hosts_path, "r+") as file: + content = file.readlines() + file.seek(0) + + for line in content: + if not any(website in line for website in website_list): + file.write(line) + + file.truncate() + + time.sleep(3600) # Check every hour \ No newline at end of file From ba0d4056b1d1536bdf1e54e73c5632c2254addfc Mon Sep 17 00:00:00 2001 From: Ahmad AL-Quraan Date: Thu, 9 Apr 2026 16:35:49 +0300 Subject: [PATCH 2/8] re-Implementing website-blocker design and handling error cases + adding input --- Website Blocker/README.md | 98 ++++++++-- Website Blocker/cross-platform-web_blocker.py | 169 ++++++++++++++++++ Website Blocker/cross-platform/web_blocker.py | 45 ----- Website Blocker/mac/Website_Blocker.py | 61 ------- Website Blocker/pictures/class-diagram.png | Bin 0 -> 56066 bytes 5 files changed, 255 insertions(+), 118 deletions(-) create mode 100644 Website Blocker/cross-platform-web_blocker.py delete mode 100644 Website Blocker/cross-platform/web_blocker.py delete mode 100644 Website Blocker/mac/Website_Blocker.py create mode 100644 Website Blocker/pictures/class-diagram.png diff --git a/Website Blocker/README.md b/Website Blocker/README.md index cf2197a1..feba0e79 100644 --- a/Website Blocker/README.md +++ b/Website Blocker/README.md @@ -1,17 +1,91 @@ # Description -This is real world program which blocks certain distracting website like Facebook, -Youtube etc during your work hours. About the program : What we are going to in this -program is that we will pass the link of websites which you think is distracting and the -time that you are working on your computer and program will block those website. ->Program Architecture: -Every system have host file whether it is Mac, Windows or Linux. - 1. for mac: Host file in Mac and Linux : "/etc/hosts"\ -2. for windows:- -C:\Windows\System32\drivers\etc\hosts +Website Blocker +Overview -## Usage -Insert working hours, and blacklisted websties in the script. The run: +This project is a Python-based website blocker that restricts access to selected websites during specified working hours. It modifies the system's hosts file to redirect targeted domains to the local machine, effectively preventing access. -> python web_blocker.py +The script supports both Unix-based systems and Windows by dynamically detecting the operating system and selecting the appropriate hosts file. +Features +Cross-platform support (Linux, macOS, Windows) +Time-based website blocking +Interactive selection of popular websites +Support for custom user-defined domains +Automatic cleanup of hosts file on exit +Error handling for insufficient permissions +Modular, object-oriented design +How It Works + +The program modifies the system's hosts file by adding entries that redirect selected domains (e.g., facebook.com) to 127.0.0.1. This prevents the browser from reaching the actual website. + +During non-working hours, the script restores the hosts file by removing those entries. + +Requirements +Python 3.x +Administrator/root privileges (required to modify the hosts file) +Usage +1. Run the script + +On Linux/macOS: + +sudo python3 web_blocker.py + +On Windows (run terminal as Administrator): + +python web_blocker.py +2. Select websites + +You will be prompted to: + +Choose from a list of common websites +Or enter custom domains +3. Set working hours + +Enter: + +Start hour (0–23) +End hour (0–23) + +If invalid input is provided, default values (8–16) will be used. + +Example + +If you select: + +facebook.com +youtube.com + +The script will add entries like: + +127.0.0.1 facebook.com +127.0.0.1 www.facebook.com +Important Notes +The script must be run with administrator/root privileges. +Modifying the hosts file affects system-wide network behavior. +The program automatically restores the hosts file when it is stopped using Ctrl+C. +Project Structure +Website Blocker/ +│ +├── cross-platform/ +│ └── web_blocker.py +│ +├── mac/ +│ └── Website_Blocker.py +│ +└── README.md +Improvements Over Original Implementation +Refactored into an object-oriented design +Added cross-platform compatibility +Introduced interactive user input +Improved timing responsiveness +Added safe cleanup on exit +Improved error handling and reliability +Future Improvements +Command-line arguments support +Configuration file for persistent settings +Logging system +Unit testing +License + +This project is part of a public repository intended for educational and practical use. diff --git a/Website Blocker/cross-platform-web_blocker.py b/Website Blocker/cross-platform-web_blocker.py new file mode 100644 index 00000000..4dee0317 --- /dev/null +++ b/Website Blocker/cross-platform-web_blocker.py @@ -0,0 +1,169 @@ +import time +import platform +import signal +import sys +from datetime import datetime + +# Flake8 and mypy check - clean code, type hints, and comments for clarity + + +class WebsiteBlocker: + def __init__(self, + websites: list, + start_hour: int = 8, + end_hour: int = 16) -> None: + self.websites = websites + self.start_hour = start_hour + self.end_hour = end_hour + self.redirect = "127.0.0.1" + self.hosts_path = self.get_hosts_path() + + # ---------------------------- + # OS handling + # ---------------------------- + def get_hosts_path(self) -> str: + if platform.system() == "Windows": + return r"C:\Windows\System32\drivers\etc\hosts" + return "/etc/hosts" + + # ---------------------------- + # Time logic + # ---------------------------- + def is_working_hours(self) -> bool: + now = datetime.now() + return self.start_hour <= now.hour < self.end_hour + + # ---------------------------- + # Blocking logic + # ---------------------------- + def block_websites(self) -> None: + try: + with open(self.hosts_path, "r+") as file: + content = file.read() + + for site in self.websites: + entry = f"{self.redirect} {site}" + if entry not in content: + file.write(entry + "\n") + + except PermissionError: + print("❌ Please run the script as administrator/root") + sys.exit(1) + + # ---------------------------- + # Unblocking logic + # ---------------------------- + def unblock_websites(self) -> None: + with open(self.hosts_path, "r+") as file: + lines = file.readlines() + file.seek(0) + + for line in lines: + if not any(site in line for site in self.websites): + file.write(line) + + file.truncate() + + # ---------------------------- + # Cleanup on exit + # ---------------------------- + def cleanup(self, signum=None, frame=None) -> None: + print("\n🧹 Cleaning up hosts file...") + self.unblock_websites() + sys.exit(0) + + # ---------------------------- + # Main loop + # ---------------------------- + def run(self) -> None: + print("🚀 Website Blocker running...") + + # Handle Ctrl + C safely -> Delete /etc/hosts or + # "C:\Windows\System32\drivers\etc\hosts" entries after + + signal.signal(signal.SIGINT, self.cleanup) + + while True: + if self.is_working_hours(): + print("🔒 Blocking websites...") + self.block_websites() + else: + print("🔓 Unblocking websites...") + print("⏰ Outside of working hours. Websites are accessible.") + self.unblock_websites() + + time.sleep(5) # responsive check + + +# ---------------------------- +# User input for websites +# ---------------------------- +def get_user_websites() -> list: + options = { + "1": "facebook.com", + "2": "youtube.com", + "3": "instagram.com", + "4": "twitter.com", + "5": "gmail.com", + "6": "\033[33mCustom: Enter your own domains\033[0m", + } + + print("- Select websites to block (comma separated):") + for key, value in options.items(): + print(f"{key}) {value}") + + print() + selected = [] + choices = input("Your choice: ").split(",") + # Process selected options + for choice in choices: + choice = choice.strip() + if choice in options and choice != "6": + selected.append(options[choice]) + selected.append("www." + options[choice]) + elif choice == "6": + custom_sites = input("Enter custom domains (comma separated): ") + for site in custom_sites.split(","): + site = site.strip() + if site: + selected.append(site) + selected.append("www." + site) + else: + print( + f"\n\033[91mInvalid option: {choice}\n\ +Please select from the list.\033[0m" + ) + return [] + + return selected + + return selected + + +# ---------------------------- +# Entry point +# ---------------------------- +if __name__ == "__main__": + + print("\n\033[33mRun this script as administrator/root for \ +it to work properly.\033[0m\n") + + websites: list = [] + while len(websites) == 0: + websites = get_user_websites() + + if not websites: + print("No websites selected. Exiting.") + sys.exit(0) + + try: + start = int(input("Enter the starting hour (0-23) for blocking \ +(default 8): ")) + end = int(input("Enter the ending hour (0-23) for blocking \ +(default 16): ")) + except ValueError: + print("Invalid input for hours. Using default values (8-16).") + start, end = 8, 16 + + blocker = WebsiteBlocker(websites, start, end) + blocker.run() diff --git a/Website Blocker/cross-platform/web_blocker.py b/Website Blocker/cross-platform/web_blocker.py deleted file mode 100644 index 33ac918c..00000000 --- a/Website Blocker/cross-platform/web_blocker.py +++ /dev/null @@ -1,45 +0,0 @@ -import time -import platform -from datetime import datetime as dt - -# Detect OS and set hosts path -if platform.system() == "Windows": - hosts_path = r"C:\Windows\System32\drivers\etc\hosts" -else: - hosts_path = "/etc/hosts" - -redirect = "127.0.0.1" - -website_list = [ - "www.facebook.com", "facebook.com"] - -START_HOUR = 8 -END_HOUR = 16 - -while True: - now = dt.now() - start = dt(now.year, now.month, now.day, START_HOUR) - end = dt(now.year, now.month, now.day, END_HOUR) - - if start < now < end: - print("Working hours...") - - with open(hosts_path, "r+") as file: - content = file.read() - - for website in website_list: - if website not in content: - file.write(f"{redirect} {website}\n") - - else: - with open(hosts_path, "r+") as file: - content = file.readlines() - file.seek(0) - - for line in content: - if not any(website in line for website in website_list): - file.write(line) - - file.truncate() - - time.sleep(3600) # Check every hour \ No newline at end of file diff --git a/Website Blocker/mac/Website_Blocker.py b/Website Blocker/mac/Website_Blocker.py deleted file mode 100644 index 17af6f09..00000000 --- a/Website Blocker/mac/Website_Blocker.py +++ /dev/null @@ -1,61 +0,0 @@ - Run this script as root - -import time -from datetime import datetime as dt - -# change hosts path according to your OS -hosts_path = " -/etc/hosts & quot -# localhost's IP -redirect = " -127.0.0.1 & quot - -# websites That you want to block -website_list = -[ & quot - www.facebook.com & quot, & quot - facebook.com" - , - & quot - dub119.mail.live.com" - , & quot - www.dub119.mail.live.com" - , - & quot - www.gmail.com" - , & quot - gmail.com" - ] - -while True: - - # time of your work - if dt(dt.now().year, dt.now().month, dt.now().day, 8) - < - dt.now() & lt - dt(dt.now().year, dt.now().month, dt.now().day, 16): - print( & quot - Working hours... & quot - ) - with open(hosts_path, 'r+') as file: - content = file.read() - for website in website_list: - if website in content: - pass - else: - # mapping hostnames to your localhost IP address - file.write(redirect + " - & quot - + website + " - \n & quot - ) - else: - with open(hosts_path, 'r+') as file: - content = file.readlines() - file.seek(0) - for line in content: - if not any(website in line for website in website_list): - file.write(line) - - # removing hostnmes from host file - file.truncate() diff --git a/Website Blocker/pictures/class-diagram.png b/Website Blocker/pictures/class-diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..8ca378d514d2cd727632798671f4f57e53c5921d GIT binary patch literal 56066 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 Date: Thu, 9 Apr 2026 16:45:53 +0300 Subject: [PATCH 3/8] Revise README for clarity and completeness Updated README.md to enhance project description, features, usage instructions, and improvements. --- Website Blocker/README.md | 119 +++++++++++++++++++++++--------------- 1 file changed, 71 insertions(+), 48 deletions(-) diff --git a/Website Blocker/README.md b/Website Blocker/README.md index feba0e79..902004a5 100644 --- a/Website Blocker/README.md +++ b/Website Blocker/README.md @@ -1,91 +1,114 @@ -# Description +# Website Blocker -Website Blocker -Overview + +##Overview This project is a Python-based website blocker that restricts access to selected websites during specified working hours. It modifies the system's hosts file to redirect targeted domains to the local machine, effectively preventing access. The script supports both Unix-based systems and Windows by dynamically detecting the operating system and selecting the appropriate hosts file. -Features -Cross-platform support (Linux, macOS, Windows) -Time-based website blocking -Interactive selection of popular websites -Support for custom user-defined domains -Automatic cleanup of hosts file on exit -Error handling for insufficient permissions -Modular, object-oriented design -How It Works + + +## Features +* Cross-platform support (Linux, macOS, Windows) +* Time-based website blocking +* Interactive selection of popular websites +* Support for custom user-defined domains +* Automatic cleanup of hosts file on exit +* Error handling for insufficient permissions +* Modular, object-oriented design + + + +##How It Works The program modifies the system's hosts file by adding entries that redirect selected domains (e.g., facebook.com) to 127.0.0.1. This prevents the browser from reaching the actual website. During non-working hours, the script restores the hosts file by removing those entries. -Requirements + +![simple-class-diagram](pictures/class-diagram.png) + + + +## Requirements + Python 3.x Administrator/root privileges (required to modify the hosts file) -Usage + + +## Usage + 1. Run the script On Linux/macOS: +```bash sudo python3 web_blocker.py +``` On Windows (run terminal as Administrator): +```bash python web_blocker.py +``` + + 2. Select websites You will be prompted to: -Choose from a list of common websites -Or enter custom domains +* Choose from a list of common websites +* Or enter custom domains + + 3. Set working hours Enter: - -Start hour (0–23) -End hour (0–23) +* Start hour (0–23) +* End hour (0–23) If invalid input is provided, default values (8–16) will be used. -Example + + +## Example If you select: -facebook.com -youtube.com +* facebook.com +* youtube.com The script will add entries like: +```bash 127.0.0.1 facebook.com 127.0.0.1 www.facebook.com +``` + Important Notes -The script must be run with administrator/root privileges. -Modifying the hosts file affects system-wide network behavior. -The program automatically restores the hosts file when it is stopped using Ctrl+C. -Project Structure -Website Blocker/ -│ -├── cross-platform/ -│ └── web_blocker.py -│ -├── mac/ -│ └── Website_Blocker.py -│ -└── README.md -Improvements Over Original Implementation -Refactored into an object-oriented design -Added cross-platform compatibility -Introduced interactive user input -Improved timing responsiveness -Added safe cleanup on exit -Improved error handling and reliability -Future Improvements -Command-line arguments support -Configuration file for persistent settings -Logging system -Unit testing -License +* The script must be run with administrator/root privileges. +* Modifying the hosts file affects system-wide network behavior. +* The program automatically restores the hosts file when it is stopped using Ctrl+C. + + +## Improvements Over Original Implementation +* Refactored into an object-oriented design +* Added cross-platform compatibility +* Introduced interactive user input +* Improved timing responsiveness +* Added safe cleanup on exit +* Improved error handling and reliability + + + +## Future Improvements +* Command-line arguments support +* Configuration file for persistent settings +* Logging system +* Unit testing + + +## License This project is part of a public repository intended for educational and practical use. From 6bb8691e6b036e53d9f07e431759dd255f14a9cf Mon Sep 17 00:00:00 2001 From: ZAX_80 Date: Thu, 9 Apr 2026 16:46:03 +0300 Subject: [PATCH 4/8] Update README.md --- Website Blocker/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Website Blocker/README.md b/Website Blocker/README.md index 902004a5..f4c95d12 100644 --- a/Website Blocker/README.md +++ b/Website Blocker/README.md @@ -1,7 +1,7 @@ # Website Blocker -##Overview +## Overview This project is a Python-based website blocker that restricts access to selected websites during specified working hours. It modifies the system's hosts file to redirect targeted domains to the local machine, effectively preventing access. From 0583ffb9d2b8a392c92e9013272787c7e898776b Mon Sep 17 00:00:00 2001 From: ZAX_80 Date: Thu, 9 Apr 2026 16:47:04 +0300 Subject: [PATCH 5/8] Update README.md --- Website Blocker/README.md | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Website Blocker/README.md b/Website Blocker/README.md index f4c95d12..d1bf84f0 100644 --- a/Website Blocker/README.md +++ b/Website Blocker/README.md @@ -39,31 +39,27 @@ Administrator/root privileges (required to modify the hosts file) ## Usage + 1. Run the script On Linux/macOS: - ```bash sudo python3 web_blocker.py ``` On Windows (run terminal as Administrator): - ```bash python web_blocker.py ``` 2. Select websites - You will be prompted to: - * Choose from a list of common websites * Or enter custom domains 3. Set working hours - Enter: * Start hour (0–23) * End hour (0–23) @@ -75,18 +71,16 @@ If invalid input is provided, default values (8–16) will be used. ## Example If you select: - * facebook.com * youtube.com The script will add entries like: - ```bash 127.0.0.1 facebook.com 127.0.0.1 www.facebook.com ``` -Important Notes +## Important Notes * The script must be run with administrator/root privileges. * Modifying the hosts file affects system-wide network behavior. * The program automatically restores the hosts file when it is stopped using Ctrl+C. From 60280942ca26ca75c7c56bce41d08a4cf4976b2e Mon Sep 17 00:00:00 2001 From: ZAX_80 Date: Thu, 9 Apr 2026 16:47:16 +0300 Subject: [PATCH 6/8] Update README.md --- Website Blocker/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Website Blocker/README.md b/Website Blocker/README.md index d1bf84f0..e416953c 100644 --- a/Website Blocker/README.md +++ b/Website Blocker/README.md @@ -20,7 +20,7 @@ The script supports both Unix-based systems and Windows by dynamically detecting -##How It Works +## How It Works The program modifies the system's hosts file by adding entries that redirect selected domains (e.g., facebook.com) to 127.0.0.1. This prevents the browser from reaching the actual website. From 3b7ef8c2c95a8de545f1c0e79f9440c8d290e804 Mon Sep 17 00:00:00 2001 From: Ahmad AL-Quraan Date: Thu, 9 Apr 2026 16:49:43 +0300 Subject: [PATCH 7/8] Add description file for detailed changes --- Website Blocker/description.txt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 Website Blocker/description.txt diff --git a/Website Blocker/description.txt b/Website Blocker/description.txt new file mode 100644 index 00000000..8245e5ab --- /dev/null +++ b/Website Blocker/description.txt @@ -0,0 +1,21 @@ +I implemented my contribution by refactoring the original website blocker script into a modular, object-oriented design that improves structure, reliability, and usability. + +First, I introduced a WebsiteBlocker class to encapsulate the core functionality of the application. This class separates responsibilities into clear methods: + +is_working_hours() determines whether blocking should be active based on the current time +block_websites() adds entries to the hosts file +unblock_websites() safely restores the hosts file +run() manages the main execution loop +cleanup() ensures that any changes to the hosts file are reverted when the program is interrupted + +To support multiple operating systems, I implemented a helper method get_hosts_path() that dynamically selects the correct hosts file path depending on whether the script is running on Windows or a Unix-based system. This builds on the cross-platform idea introduced in PR #563, but integrates it into a cleaner and more structured design. + +I improved reliability by adding proper error handling when accessing the hosts file. Specifically, I handle PermissionError to prevent the program from crashing and instead provide a clear message to the user about running the script with administrator or root privileges. + +I also enhanced the usability of the script by adding an interactive interface that allows users to select commonly blocked websites or input custom domains without modifying the source code. This makes the tool more practical for real-world usage. + +Additionally, I improved the responsiveness of the script by replacing long fixed delays with shorter intervals (time.sleep(5)), allowing the program to react more quickly to changes in working hours. + +Finally, I implemented a cleanup mechanism using signal handling (SIGINT) so that when the user stops the program (e.g., using Ctrl+C), any modifications made to the hosts file are automatically reverted. This addresses a key limitation in the original implementation, where stopping the script could leave the system in a blocked state. + +Overall, these changes improve the code’s structure, robustness, and user experience, while making it easier to maintain and extend in the future. From 03717e90954d2e0da6af2256d5c18d7f42c88107 Mon Sep 17 00:00:00 2001 From: Ahmad AL-Quraan Date: Thu, 9 Apr 2026 16:57:02 +0300 Subject: [PATCH 8/8] Edit README --- Website Blocker/README.md | 6 ++++-- Website Blocker/description.txt | 17 +++++++++-------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Website Blocker/README.md b/Website Blocker/README.md index e416953c..b1dca558 100644 --- a/Website Blocker/README.md +++ b/Website Blocker/README.md @@ -26,8 +26,10 @@ The program modifies the system's hosts file by adding entries that redirect sel During non-working hours, the script restores the hosts file by removing those entries. +This could be very useful for system administrators, parents, or anyone looking to improve productivity by limiting access to distracting websites during certain hours. -![simple-class-diagram](pictures/class-diagram.png) + +![simple-diagram](pictures/class-diagram.png) @@ -74,7 +76,7 @@ If you select: * facebook.com * youtube.com -The script will add entries like: +The script will add entries like to the hosts file: ```bash 127.0.0.1 facebook.com 127.0.0.1 www.facebook.com diff --git a/Website Blocker/description.txt b/Website Blocker/description.txt index 8245e5ab..98ca909b 100644 --- a/Website Blocker/description.txt +++ b/Website Blocker/description.txt @@ -1,12 +1,12 @@ -I implemented my contribution by refactoring the original website blocker script into a modular, object-oriented design that improves structure, reliability, and usability. +* I implemented my contribution by refactoring the original website blocker script into a modular, object-oriented design that improves structure, reliability, and usability. -First, I introduced a WebsiteBlocker class to encapsulate the core functionality of the application. This class separates responsibilities into clear methods: +* First, I introduced a WebsiteBlocker class to encapsulate the core functionality of the application. This class separates responsibilities into clear methods: -is_working_hours() determines whether blocking should be active based on the current time -block_websites() adds entries to the hosts file -unblock_websites() safely restores the hosts file -run() manages the main execution loop -cleanup() ensures that any changes to the hosts file are reverted when the program is interrupted + * is_working_hours() determines whether blocking should be active based on the current time + * block_websites() adds entries to the hosts file + * unblock_websites() safely restores the hosts file + * run() manages the main execution loop + * cleanup() ensures that any changes to the hosts file are reverted when the program is interrupted To support multiple operating systems, I implemented a helper method get_hosts_path() that dynamically selects the correct hosts file path depending on whether the script is running on Windows or a Unix-based system. This builds on the cross-platform idea introduced in PR #563, but integrates it into a cleaner and more structured design. @@ -18,4 +18,5 @@ Additionally, I improved the responsiveness of the script by replacing long fixe Finally, I implemented a cleanup mechanism using signal handling (SIGINT) so that when the user stops the program (e.g., using Ctrl+C), any modifications made to the hosts file are automatically reverted. This addresses a key limitation in the original implementation, where stopping the script could leave the system in a blocked state. -Overall, these changes improve the code’s structure, robustness, and user experience, while making it easier to maintain and extend in the future. +Overall, my contribution significantly enhances the structure, reliability, and usability of the website blocker while maintaining the core functionality of blocking distracting websites during working hours. +