Twitterにあって便利だったbotはできるだけBlueskyに作っておこうという試みである。そう言うわけでネタ元はこれ。1時間おきに切り取り線を呟いてくれるbot、結構便利であるのでBlueskyに作っておく。
とは言えBlueskyはそんなにタイムラインの流れが速くないので、1時間おきに線を引く必要も無かろう、と思って6時間おきでポストするようにした。完成品がこちら。
bsky.app人によってはそれでも1時間おきがいいとか要望があるかもしれないので欲しい人が適当に作って欲しい。そう言う訳でスクリプトを公開しておく。適宜弄って流用して結構であるが、多分質問とかには答えないし無保証である。
まず基本事項は以下の通り。
- PythonのatprotoでBlueskyに書き込む。スクリプトはsystemdに登録して常時起動させておく。
- ファイルはkiritori.py(本体)、kiritori.service(systemd用)、kiritori_auth.json(ログイン情報が入っている設定ファイル)、kiritori.log(ログファイル)からなる。
- RaspberryPi OSはpipが使えないのでvenvで仮想環境を作る。仮想環境のディレクトリは/home/pi/bluesky/とする。このフォルダに前記のファイル(kiritori.service)以外を保存する。
詳細な解説はしない。これを読むような人は自力でなんとかできると信じてる。と言うか面倒臭い。サクサクとディレクトリと仮想環境を作り、atprotoモジュールをインストールする。足りないものがあればエラーを見て追加すれば良い。
mkdir bluesky python3 -m venv bluesky source bluesky/bin/activate pip install atproto
本体のスクリプト:kiritori.pyはこれ。もったいぶらずドンと貼る
import sys import os import time import json import logging from atproto import Client, models import argparse from datetime import datetime, timedelta # ログの設定 log_file = '/home/pi/bluesky/kiritori.log' logging.basicConfig( filename=log_file, level=logging.INFO, # INFOレベルでログを記録(DEBUGレベルから変更) format='%(asctime)s - %(levelname)s - %(message)s' ) # コマンドライン引数の設定 def parse_args(): parser = argparse.ArgumentParser(description="Bluesky Kiritori Sen") parser.add_argument('--debug', action='store_true', help="デバッグモードでデバッグ書き込み") return parser.parse_args() # 引数を解析 args = parse_args() # 仮想環境のパスをsys.pathに追加 venv_path = '/home/pi/bluesky' sys.path.insert(0, os.path.join(venv_path, 'lib', 'python3.11', 'site-packages')) # 設定ファイルのパス CONFIG_FILE_PATH = '/home/pi/bluesky/kiritori_auth.json' # 設定ファイルを読み込む関数 def load_config(): try: with open(CONFIG_FILE_PATH, 'r', encoding='utf-8') as file: return json.load(file) except FileNotFoundError: logging.error("設定ファイルが見つかりません。") return None except json.JSONDecodeError: logging.error("設定ファイルの形式にエラーがあります。") return None # 設定を読み込み config = load_config() if config: username = config.get('username') password = config.get('password') logging.info("ユーザー名とパスワードを正常に読み込みました。") else: logging.error("設定の読み込みに失敗しました。") # 日本語の曜日を手動で定義 weekdays_ja = ['月', '火', '水', '木', '金', '土', '日'] # Blueskyに投稿 def post_to_bluesky(client): logging.info("Blueskyへの投稿を開始します。") try: # 現在の時刻を取得 now = datetime.now() # 0時の場合 if now.hour == 0: # 日付と日本語曜日を表示 weekday_ja = weekdays_ja[now.weekday()] # 日本語の曜日を取得 post_text = f"✄-------{now.strftime('%Y-%m-%d')} ({weekday_ja})------✄" else: # それ以外の時刻(通常は時:分の形式) post_text = f"✄-------{now.strftime('%H:%M')}------✄" client.send_post(post_text) logging.info(f"投稿成功: {post_text}") except Exception as e: logging.error(f"Blueskyへの投稿中にエラーが発生しました: {e}") # 次の投稿時刻まで待機する関数 def wait_until_next_run(): # 現在の時刻を取得 now = datetime.now() # 0時、6時、12時、18時のいずれかの時刻までの秒数を計算 next_run_time = None for hour in [0, 6, 12, 18]: if now.hour < hour: next_run_time = datetime(now.year, now.month, now.day, hour, 0, 0) break if next_run_time is None: # 今日の18時を過ぎている場合、次は明日の0時 next_run_time = datetime(now.year, now.month, now.day, 0, 0, 0) + timedelta(days=1) # 次回実行までの待機時間(秒) time_to_wait = (next_run_time - now).total_seconds() logging.info(f"次回の実行まで {time_to_wait / 60:.2f} 分です。") time.sleep(time_to_wait) # メイン処理 if __name__ == "__main__": # Clientのインスタンスを1回だけ作成 client = Client() client.login(username, password) # ログイン if args.debug: logging.info("デバッグモード: 即時チェックを実行します。") post_to_bluesky(client) else: logging.info("スケジュールモード: 0時、6時、12時、18時に更新チェックを実行します。") while True: post_to_bluesky(client) wait_until_next_run() # 次回の実行まで指定された時刻まで待機
次は設定ファイルのkiritori_auth.json。アカウント名とBlueskyの「プライバシーとセキュリティ」から作れるアプリパスワードを保存するので、スクリプト本体とは別に作り、chomodでパーミッションを600にして所有者のみ読み書き専用にする。
{ "username": "kiri-tori.bsky.social", "password": "****-****-****-****" }
作るファイルとしては次で最後、kiritori.serviceであるが、これは/etc/systemd/system/に作る。
[Unit] Description=Kiritorisen Service After=network.target [Service] ExecStart=/home/pi/bluesky/bin/python /home/pi/bluesky/kiritori.py WorkingDirectory=/home/pi StandardOutput=journal StandardError=journal Restart=on-failure User=pi Group=pi Environment="PATH=/home/pi/bluesky/bin:$PATH" [Install] WantedBy=multi-user.target
これでよし。kiritori.logはない場合の動作が特に定義してないのでエラーが出るかもしれない。不安なら
touch /home/pi/bluesky/kiritori.log
で作っておけばよい。
動作確認はデバッグモードがある。仮想環境で動かすことを忘れないように。
source /home/pi/bluesky/bin/activate python3 /home/pi/bluesky/kiritori.py --debug
とオプションを付けて実行すると現在の時刻が書き込まれるはずである。設定ファイルが正しく設定されるか等の確認に使える。仮想環境から抜けるときは
deactivate
で抜けられる。あとは普通にサービスに登録すれば良い。
sudo systemctl daemon-reload sudo systemctl enable kiritori.service sudo systemctl start kiritori.service sudo systemctl status kiritori.service
これで完了。問題が生じたらログファイルを読むなどして適当に対応してほしい。