ブログを書くようになってから、それなりに時間が経った。過去に自分で Movable Type をホストしていたときの記事や、はてなダイアリーに書いたりしたものは消えてしまったけど、それでも 2012 年から先の記事はまだ生きている

ところで、僕のブログ記事をもっとも楽しく読めるのは自分自身なのではないかと思う。調べ物をしているときに検索エンジンが導いてくれるページはしばしば過去の自分のブログ記事だし、何より自分の記事は読みやすい。「過去の自分が名文を書いたから」ではなく、記事を理解するのに必要な前提知識があるからである (なにせ書き手が自分自身なので)。

自分がメンテナンスしているブログの sitemap.xml をパースしてリダイレクトするプログラムを Heroku で動かし、それをブラウザの新規タブのデフォルトページに設定したこともある。

ただし、これだと新規タブを開くのが遅くなってしまう。よりよい方法はないかと模索している。

現在の暫定解は macOS の Launchd を使い、定期的にブログ記事をランダムに選んで Slack にポストするというものだ。

具体的には $HOME/LaunchAgents/slack-reminder.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>Slack Notifier 1 hour</string>
    <key>ProgramArguments</key>
    <array>
        <string>/Users/mahata/.pyenv/shims/python</string>
        <string>/Users/mahata/bin/slack-post.py</string>
    </array>
    <key>StartInterval</key>
    <integer>3600</integer>
    <key>StandardOutPath</key>
    <string>/tmp/slack-post.out</string>
    <key>StandardErrorPath</key>
    <string>/tmp/slack-post.err</string>
</dict>
</plist>

雰囲気で読めそうな気がするので詳細は割愛するけれど、これで 3600 秒ごと (つまり 1 時間ごと) に次のコマンドを実行する、と指定している。

$ /Users/mahata/.pyenv/shims/python /Users/mahata/bin/slack-post.py

なお、この plist ファイルを有効にするためには次のコマンドを実行する。

$ launchctl load $HOME/Library/LaunchAgents/slack-reminder.plist

ところで /Users/mahata/bin/slack-post.py の中身は次のようになっている。

#!/usr/bin/env python3

import urllib.request
import json
import random
import xml.etree.ElementTree as ET

urls = []

sitemaps = [
    {
        "sitemap": "https://mahata.gitlab.io/sitemap.xml",
        "startwith": "https://mahata.gitlab.io/post/20",
    },
    {
        "sitemap": "https://mahata.wordpress.com/sitemap.xml",
        "startwith": "https://mahata.wordpress.com/20",
    },
]

for sm in sitemaps:
    with urllib.request.urlopen(sm["sitemap"]) as res:
        tree = ET.XML(res.read())
        for url_block in tree.findall("{*}url"):
            url = url_block.find("{*}loc").text
            if url.startswith(sm["startwith"]):
                urls.append(url)

WEBHOOK = (
    "https://hooks.slack.com/services/xxx/xxx/xxx"
)

body = {
    "channel": "#my-channel",
    "username": "ブログ読めボット",
    "text": f"今日のハッピーブログ - {random.choice(urls)}",
    "icon_emoji": ":mario:",
    "unfurl_links": "true",
}
headers = {"Content-Type": "application/json"}

req = urllib.request.Request(WEBHOOK, json.dumps(body).encode(), headers)
with urllib.request.urlopen(req) as res:
    body = res.read()
    print(body)  # Should be "ok"

僕が保有している mahata.gitlab.iomahata.wordpress.comsitemap.xml からランダムに記事を取得して Slack に投稿するだけのコードだ (WEBHOOK やチャンネル名は実際のものとは異なる)。Slack 上では次のように見える。

Slack

これでブログ記事が定期的に Slack に投稿され、しかもプレビューが勝手に開くので使い勝手がよい。すべてがバックグラウンドで動くため遅延も気にならない。