【Mac】ある時間帯のみ、特定のサイトへのアクセスを制限したい

2022年9月26日

夜、酒を飲む習慣が身についてしまった。
 ひとりで酔っ払ってると、ひとつ怖いことがある。酔った挙句、Twitter で恥ずかしい、行儀悪い、馬鹿なことを発言してしまうのではないか。
 翌朝、ブラウザに身におぼえのない Twitter のタブがあったりして、ぞっとすることあるからね。
 飲みすぎて、記憶が飛んでいる。自分がなにをしたかなんてまったく覚えてないんだから。

さびしい中年男性は、酔って前頭葉の機能を低下させたとき、ついつい知らないひとに失礼な絡みをしてしまう可能性を持っている。さびしいから。
 このリスクを可能なかぎり避けたいと思い、スクリプトを考えてみた。

6 時間、特定のサイトへのアクセスを制限するスクリプト

筆者が酒を飲みはじめるのは、だいたい 22 時ごろからだ。
 それからだいたい 2 時間くらいは飲んでいると思う。ひとりで。
 最長でも 6 時間は越えないだろう。そう考えて、起動したら 6 時間、Twitter にアクセスできないスクリプトを目指した。

📝 siteblock.sh

#!/bin/sh

INT=2160
blocklist=(twitter.com syosetu.com)

while [ $INT -ge 0 ]
do

    URL=$(osascript -e 'tell app "safari" to get the url of the current tab of window 1')

    for site in "${blocklist[@]}"
    do
        if echo "$URL" | grep -sq "$site"; then
            osascript -e 'tell app "safari" to close the current tab of window 1'
        fi
    done
    ((INT--))
    sleep 10
done

上記スクリプトは、10 秒ごとに safari で開いているタブをチェックし、Twitter と syosetu.com(「小説家になろう」)を開いていた場合、タブを自動で閉じる、というものである。
(筆者は「なろう」さんのコミュニティーにも酔って迷惑をかける可能性があるので、追加した)

INT=2160
 というのは時間の指定だ。
 6 時間を秒数にすると、3600 * 6 で 21600 秒ということになる。10 秒ごとなので、10 で割ると 2160 回だ。変数 INT を 10 秒ごとに 1 引いていって、ゼロになったらループを終了する。
 つまり、
while [ $INT -ge 0 ]
 ということになる。

URL という変数は、現在開いているタブの URL をアップルスクリプトで取得したものだ。
blocklist という変数は、閲覧を制限したいサイトのドメインを列挙した配列である。
 変数 URL で取得した、閲覧しているサイトのアドレスを、blocklist に照らしあわせて、twitter.com と syosetu.com という文字列が含まれていた場合、

tell app "safari" to close the current tab of window 1

というアップルスクリプトでタブを閉じる。
 筆者の環境では今のところ動作している。
 なんか、仕事中に pixiv を閲覧してしまう、という謎の行動も防げるかもしれない。

夜 10 時に自動でスクリプトを起動する

酔っ払いなんて当てにならない。いつも夜 10 時に上記のスクリプトを実行するとは限らない。
 なので macOS の Launchd を使い、自動で実行することにする。

Launchd については、下記の記事が詳しい。参考にさせていただきました、ありがとうございます。

🔗 launchdで定期的にスクリプトを実行 – Qiita

📝 site.block.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>site.block</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/sh</string>
        <string>/Users/USERNAME/bin/siteblock.sh</string>
    </array>
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>21</integer>
        <key>Minute</key>
        <integer>30</integer>
    </dict>
</dict>
</plist>

上記の xml を site.block.plist という名前で、~/Library/LaunchAgents フォルダに保存した。
 ファイル名は、上記の Label という項目と同じにする必要がある。
 ProgramArguments に、シェルスクリプトのパスを記述する。筆者の場合はホームディレクトリの bin というフォルダにスクリプトを置いている。
 StartCarendarInterval に実行する時間を記述する。いつも 22 時ごろから飲みはじめるのだが、自分を信用していないので 21 時 30 分に仕掛けることにした。

あとはターミナルで、下記を実行するだけだ。
launchctl load ~/Library/LaunchAgents/site.block.plist
 これでもう、再起動しようがなんだろうが、夜 9 時半から 6 時間 Twitter にアクセス出来なくなる。頼もしい。
 この設定を解除する場合は、ターミナルで下記を実行する。
launchctl unload ~/Library/LaunchAgents/site.block.plist
 なんらかの緊急事態で、どうしても Twitter にアクセスする必要がある場合は、safari 以外のブラウザを使用すればいいだろう。

こんなもん作るくらいなら、酒やめたら、という意見もあろうかと思う。
 思うんだけどねぇ。
 やめらんねーんだなぁこれが。

アプリを利用する

似たような目的を達成する、1focus というアプリがある。

🔗 「1Focus: ウェブサイトとアプリブロッカー」をMac App Storeで

サイトだけではなく、アプリの実行も制限できる。
 ただ、スケジュールを組むには月 200 円/年 1,100 円という絶妙な料金設定のサブスクを支払わねばならない(2022年6月現在)。とはいえ、11,000 円で 10 年も使えるとなれば、案外買いか。

試してみたところ、筆者の環境(MacBook Air 2020 late,macOS Monterey)では良好に動作した。safari だけではなく、Google Chrome など他のブラウザでも、設定したサイトへのアクセスを制限できて、いいかもしれない。

追記

追記 2022.08.18

上記のシェルスクリプトだと、スリープ中に変数 INT の引き算が止まってしまい、スリープ解除した後に動作が続いてしまうことに気づいた。真っ昼間、しらふなのに twitter が見られない、という事態がたびたび発生する。
 なので以下のように修正した。

📝 siteblock2.sh

#!/bin/sh

INT=14400
LMT=$(echo $(($(date +%s) + $INT)))
blocklist=(twitter.com syosetu.com)

while [ $(date +%s) -lt $LMT ]
do

    URL=$(osascript -e 'tell app "safari" to get the url of the current tab of window 1')

    for site in "${blocklist[@]}"
    do
        if echo "$URL" | grep -sq "$site"; then
            osascript -e 'tell app "safari" to close the current tab of window 1'
        fi
    done
    sleep 10
done

UNIX タイムに目標とする秒数を足し、現在の時刻が目標時刻以下だった場合、while で開いているサイトの監視を続ける、という感じ。
 これなら 10 秒ごとに現在時刻を参照するので、上に述べたような事態は発生しないんじゃないかな、たぶんだけど。

追記 2022.9.26

上述のスクリプトでも、launchd による起動時間がズレると、昼間でもスクリプトが有効になってしまう。いったいなんなんだろう。わしゃ馬鹿なんでしょうか。
 しょうがないから以下のようにした。

📝 siteblock3.sh

#!/bin/sh

NOW=$(date "+%H%M")
blocklist=(twitter.com syosetu.com)

while [ $NOW -le 300 -o $NOW -ge 2130 ]
do

    URL=$(osascript -e 'tell app "safari" to get the url of the current tab of window 1')

    for site in "${blocklist[@]}"
    do
        if echo "$URL" | grep -sq "$site"; then
            osascript -e 'tell app "safari" to close the current tab of window 1'
        fi
    done
    sleep 10
    NOW=$(date "+%H%M")
done

けっきょくこれだな。この単純な形。
 21 時 30 分から午前 3 時まで、ということを while の条件文に記載しておく。んで、10 秒ごとに現在時刻を更新していくと。
 ただここへきて、ツイッターを MacBook Air のブラウザで見てるのって、筆者だけなんじゃないかということに気づいたが、まぁもういいや。