Skip to content

Instantly share code, notes, and snippets.

@serif
Last active November 10, 2023 07:18
Show Gist options
  • Save serif/9a6bae4e4e0fcad0f69968451395e402 to your computer and use it in GitHub Desktop.
Save serif/9a6bae4e4e0fcad0f69968451395e402 to your computer and use it in GitHub Desktop.
webblocker.py suggestions

Response to https://gist.github.com/Thomas-0001111111/e40b05c3ed0da41a3d7308b90ef8383f

Preparation

Develop using local copy

Test any script that affects a system file using a local copy until it's complete. cd to your project folder, then in the terminal:

cp /etc/hosts ./
cp /etc/hosts ./hosts_orig

After testing the script, return the local copy to its original state for further testing with:

cp hosts_orig hosts

The default hosts file contains necessary entries. If these have been removed from yours, get them from here: How to Reset Hosts File to Default on Mac and Windows PC

Run script directly

To invoke the script directly, add a crunchbang to the top of the .py file:

#!/usr/bin/env python3

Make the file executable in the terminal:

chmod +x webblocker.py

Now you can run it directly without invoking it through Python:

./webblocker.py

And with sudo when ready to point it at the real system file.

sudo ./webblocker.py

Suggestions

Problem

The hosts file expects domains, not URLs, so "www.bbc.co.uk" instead of "https://www.bbc.co.uk/news".

websitelist = [
    'www.bbc.co.uk',
    'www.dailymail.co.uk',
    'www.facebook.com',
    'www.youtube.com',
]

DRY

Following DRY (Don't Repeat Yourself) and not re-opening the file in append mode when it's already open in read+, here's how I might organize this:

#!/usr/bin/env python3
import datetime as dt

# hostpath = '/private/etc/hosts'   # macOS 11+
# hostpath = '/etc/hosts'           # Linux, macOS X
hostpath = 'hosts'                  # Local testing
domains = [
    'www.bbc.co.uk',
    'www.dailymail.co.uk',
    'www.facebook.com',
    'www.youtube.com',
]

def is_blocktime():
    start = dt.time(6, 0)
    end = dt.time(18, 0)
    now = dt.datetime.now().time()
    return start <= now < end

with open(hostpath, 'r+') as file:
    content = file.read()
    if is_blocktime():
        # Block
        print('Time to focus now, Thomas!')
        for domain in domains:
            if not domain in content:
                content += f'\n127.0.0.1 {domain}'
    else:
        # Unblock
        print('Enjoy your free time, Thomas!')
        new_lines = []
        for line in content.splitlines():
            if not any(domain in line for domain in domains):
                new_lines += [line]
        content = '\n'.join(new_lines)
    # Write
    if not content.endswith('\n'):
        content += '\n'
    file.seek(0)
    file.write(content)
    file.truncate()

Note that I've changed the import statement so we can access datetime.time. While testing, you can add return True or return False as the first line of is_blocktime() to override it, and in the terminal, cat hosts to see what's going on. Once you're satisfied, comment-out:

hostpath = 'hosts'

and un-comment:

hostpath = '/private/etc/hosts'

Automate

Use crontab to make the script automatically run every hour.

sudo crontab -e

Add this line:

0 * * * * /absolute/path/to/webblocker.py

Format:

* * * * *  command to execute
│ │ │ │ │
│ │ │ │ └─── day of week (0 - 6) (0 to 6 are Sunday to Saturday, or use names; 7 is Sunday, the same as 0)
│ │ │ └──────── month (1 - 12)
│ │ └───────────── day of month (1 - 31)
│ └────────────────── hour (0 - 23)
└─────────────────────── min (0 - 59)

You can get the absolute path to your working directory by running pwd (print working directory) in the terminal within your project folder.

@Thomas-0001111111
Copy link

Thanks a lot for this and taking the time out to help a stranger. I feel I've learnt more reading this for 10 mins than watching a Youtube video. I'll try this out to see if it works!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment