開発しているBlueskyクライアントアプリbsky-sh-cli (Bluesky in the shell)の新バージョンv0.9.0をリリースしました。この記事では本リリースに関して補足情報を記載します。
なおいつにも増して同人誌のあとがき的にくっさい表現・露悪・スラング・自分語りが多いので御注意ください。
スレッド投稿機能でのポスト個別オプション指定(postsコマンドでの区切りセクションオプションディレクティブ機能)
なんのことやらですよね。
bsky-sh-cliでのスレッド投稿機能
bsky-sh-cliでは、一度のコマンド実行で複数のポスト(代表的なパターンでは数珠繋ぎにリプライを繋げるスレッド投稿)を行うposts
コマンドがあります。
ポスト1個目
↑
ポスト2個目(ポスト1個目へのリプライ)
↑
ポスト3個目(ポスト2個目へのリプライ)
:
このコマンドでは--separator-prefix
オプションを指定することにより、ひとつの指定単位(ファイル、パラメタ、標準入力)に複数のポストを含ませることができます。複数のポスト間の区切りはオプションで指定した文字列になります。たとえばposts.txtが以下の内容の場合:
########
ポスト1個目
########
ポスト2個目
########
ポスト3個目
以下のコマンドを実行すると、前述のようなスレッド投稿になります。--separator-prefix
オプションで指定した文字列(########
)で始まる行は、投稿内容からは無視されます。
bsky posts --text-files 'posts.txt' --separator-prefix '########'
なお参考として、区切り文字列から行末までは(後述のディレクティブ機能を除き)無視され、区切り文字列で始まる行の間が空または改行のみで構成される内容も無視されますので、以下のように複数行コメントのようなことも可能です。
######## ポスト1
######## スレッド先頭のポスト
ポスト1個目
######## ポスト2
######## ポスト1個目へのリプライ
ポスト2個目
######## ポスト3
######## ポスト2個目へのリプライ
ポスト3個目
区切りセクションオプションディレクティブ機能
前述のように--separator-prefix
オプションで指定した文字列(########
)で始まる行で区切ったポストの単位を「区切りセクション」と呼びます。
「オプション」とはposts
コマンドで他に指定できる--langs
オプション(言語コード指定)や--url
オプション(ポスト後のURL短縮表示方法指定)で、これらのオプションを区切りセクションごとに指示(ディレクティブ)することができます。
具体的には--separator-prefix
オプションで指定した文字列の直後に%
を記述し、そのあとにコマンドラインパラメタに指定するのと同様にオプションを記述します。たとえばポストの言語コードを英語(en)で指定するにはコマンドラインパラメタでは以下のように指定します。
bsky posts --text 'Yo! Bluesky' --langs 'en'
前述のposts.txtの例で、1個目と2個目のポストは英語(en)、3個目のポストは日本語(ja)としたい場合、posts.txtを以下のように記述します(ポスト内容と言語コードが一致していないことは無視してください)。
########% --langs 'en'
ポスト1個目
########
ポスト2個目
########% --langs 'ja'
ポスト3個目
2つ目の区切りセクションにオプションを指定していませんが、オプション指定はそれまでの内容が継承されますので、1つ目と同じ英語(en)となります。3つ目の区切りセクションでは日本語(ja)を指定しています。
この例では区切りセクションによってオプション指定を変えるようなトリッキーな指定をしていますが、他の用法として、コマンド実行時のパラメタオプションでの指定忘れを防ぐために、ポスト内容を記述するテキストの先頭にオプションを記述しておくという使い方などが考えられます。
セルフアップデート機能(updateコマンド)
現在はディストリビューションパッケージのような大層なことはしていないので、インストールや新バージョンへのアップデートは手動でGitHubリポジトリからアーカイブを持ってきてinstall.sh
を実行(場合によってはインストール先も指定)しなければなりませんが、アップデートに関してbskyコマンド自身でGitHubリポジトリからアーカイブを(テンポラリディレクトリに)持ってきて、install.sh
を実行(インストール先は実行したbskyコマンドの所在が基準)する簡易アップデート機能を設けました。
同様なしくみで初期導入用にcurl https://raw.githubusercontent.com/bills-appworks/bsky-sh-cli/main/<リモートインストーラ> | sh
的なものも今後考えたいと思います。
軽微な修正
実装的にはちっとも軽微ではなかった(他と同じか大きいくらい)のですが、利用者へのインパクトはあまりないのでここで吐き出します。
結果的にはposts
コマンドでのプレビュー(--preview
)が性能改善し、ケースによっては50%を超える性能向上をしました。CHANGELOGにも「スレッド投稿プレビュー機能性能改善」(ドヤッ)と書きかけたのですが、「くそくそおせーよ」が「くそおせーよ」になった程度なので引っ込めました。
契機はリリース候補版作成時に「区切りセクションオプションディレクティブ機能」にバグが見つかったことによります。事象的にはオプション指定の効果が想定と異なるものでした。
調査の結果、「区切りセクションオプションディレクティブ」での記述オプションの解釈処理で副作用が発生し、その後の処理に影響を与えていました。関連する部分は以下のような処理構造になっています。
- 各ポストのサイズチェック(300文字超過)
- 各ポストのBlueskyへの投稿処理またはプレビュー表示処理
「区切りセクションオプションディレクティブ機能」実装にあたり、1の処理最終ステップのオプション解釈情報が、2の処理に影響していたため、オプションを指定していない先頭セクションに全ポスト処理後の最終的なオプション効果が波及するなど、状態の競合が各所で発生していました。
ダメ実装ですありがとうございました、ではありますが、言い訳としてはシェルスクリプト実装による制約もあります。
シェルスクリプトでは変数はグローバル変数になります。「local
コマンドで局所化できるでしょ?」その通りです。ただしできるだけBash固有機能等を使わずBourne Shell互換範囲内での実装を目標としているbsky-sh-cliではlocal
コマンドの導入は避けています。マゾですね、いやシェルスクリプト実装の時点でマゾですが。
そういうことでそれまでは一度指定したオプションの内容が変わることはまず無いため、関連変数名は各メソッド(関数)で重複してもまぁいいやという乱暴な実装で事足りていました。「区切りセクションオプションディレクティブ機能」が現れるまでは。
前提を(自ら)ひっくり返してしまったためさぁ大変です。汚い逃げ実装もありますが、コールスタックを自前実装するか、関数ごとに変数名をユニークにするなど、各関数をリエントラント(再入可能)にするしかありません。しました。echo→printf以来の規模のリファクタリングになりました。
などなど四苦八苦しているうちに気づきました。1の処理でテキスト全文パースして、2の処理でテキスト全文パースして…さらに後で気づきましたがその前にポスト数上限チェック(スパム防止のためのセルフガイドライン)でもテキスト全文パースしていました…その場しのぎの実装の結果とはいえ酷い、そして遅い。
1などのチェックと, 2のBlueskyへの投稿処理(およびプレビュー表示処理)をポストごとに合わせてしていないのは、2個目以降のポストでサイズ超過等による中断が発生した場合、それまでの投稿は実行されてしまっており巻き戻って削除しない限り投稿したスレッドが中途半端になってしまうためです。エラーになったら投稿済みは削除する、という投機的な処理はできるだけ避けたいと考えています。
プレビュー処理では2の処理中に中断しようとも実害は発生しません。そのためプレビュー時は2の処理の中でチェックも行うようにし、事前のチェックはスキップするようにしました。他にもリンクカードで現在は画像URLを表示していないのでプレビューでは画像も生成しないなど、各種対応によりプレビュー時の性能が改善しています。
しかし(プレビューでない)Bluesky投稿処理は従来と同じく遅いままであるため、その改善が今後の課題です。