先打脸#
以前書いた語雀を使ってブログを公開する方法は全く役に立たなかったが、iPhone 13 pm を手に入れた後、iOS には非常に優れた効率アプリである Shortcuts があることを思い出した(ハンマーを持っていると釘が見えやすい?)。そこで、iOS クライアントを作成することなく、iPhone を使って静的ブログを直接公開する方法を考えた。
前置知识#
API を使って GitHub リポジトリを更新する#
このプロセスを実現するためには、まず API を使って GitHub リポジトリを更新する方法を知っておく必要がある。この問題については以前も触れたが、ファイルを更新するのは比較的理解しやすい。
ここで再度復習してみよう。このステップは以前の記事とほぼ同じだが、少し改善した:
- Ref を取得する:Ref はGit の参照を指し、Ref が commit を指すことでその commit を見つけやすくなる。そうでなければ、その SHA-1 値を使って探さなければならない。例えば、
heads/master
は Ref の一例で、これを使って master の最新のコミットを見つけることができる。言い換えれば、Ref を取得するこのステップは最新の commit のハッシュ値を取得することだ。 - Commit 情報を取得する:現在の Commit の tree の sha を取得するために使用し、5 ステップで tree を生成する際に古い tree の情報が必要になる。
- Blob を生成する:通常のローカルコミットの add 操作に相当する。
- Tree を生成する:新しい tree を構築する。この時必要なパラメータ base_tree は第 2 ステップの Commit 情報から来る。(実際には
/git/trees
インターフェースを使うと、このステップで直接 content を渡すことができ、システムが自動的に blob を生成するので、第 3 ステップのインターフェースを省略できる) - Commit を生成する:新しい tree を使って commit を作成し、これでコミットが完了する。
- Ref を更新する:master の Ref を先ほどコミットしたバージョンに指すようにする。
核心コード(関数はすべてインターフェースを呼び出す)はほぼ以下のようになる:
const updateGitHubRes = async function ({
blob,
encoding,
path,
commitMessage,
}) {
const ref = await getRef()
const commitSha = ref.object.sha
const commitInfo = await getCommitInfo(commitSha)
const commitTreeSha = commitInfo.tree.sha
const blob = await createBlob(blob, encoding)
const tree = await createTree(commitTreeSha, path, blob.sha)
const newCommit = await createCommit(commitSha, tree.sha, commitMessage)
await updataRef(newCommit.sha)
}
以前の GitHub API ドキュメントでは、リポジトリを更新する手順が複数のページに分かれていたが、今は単一のページに集約されていて、参照が便利になった。また、インターフェースを呼び出すにはpersonal access tokenが必要で、リクエストヘッダーにAuthorization: 'token ' + process.env.GH_TOKEN
を追加する必要がある。
怠け者の方法#
その後、ドキュメントでより便利な更新インターフェース/repos/{owner}/{repo}/contents/{path}
を見つけた。
このインターフェースを使えば、git のコミット原理を気にせずに GitHub リポジトリを直接更新できるので、便利だ。
Serverless Function#
Serverless とは簡単に言うと、特定のアドレスに関数を掛けて、そのアドレスがアクセスされると対応する関数が実行されるということだ。この関数内でリクエストのさまざまな情報を取得し、データを処理して返すだけの軽量なインターフェースだ。
このシナリオでは、Serverless は完璧で、personal access token を使うことでシステムにログインする必要がなく、状態の問題がない。また、GitHub のインターフェースに関しては、海外のサービスを使う方が国内でサーバーを立てるよりも速い。
Serverless Function を提供する業者は多いが、私は比較的慣れているvercelを選ぶことにした。毎月無料枠があり、通常この需要では課金される量にはならない(大量に画像をアップロードしない限り)。
ショートカット#
元々は Workflow という名前で、後に iOS に標準搭載されたアプリで、可視化されたスクリプトツールと言える。理解するのは難しくないが、操作に慣れるまでに少し時間がかかる(しかも iPhone での操作は少し不便で、ページのチラつきバグが頻繁に発生するので、iPad の方が快適だと感じる)。
公開機能を実現するための核心は、内部のGet contents of URL
ステップで、基本的には Ajax リクエストに相当し、自由にネットワークインターフェースをリクエストできる。この機能があれば、遊び方は無限大だ。
ネットワークインターフェースをリクエストするだけでなく、url-scheme を利用して本機のプログラムの隠れた入口に直接アクセスすることもできる。例えば、健康コード、支払いコード、QR コードスキャンなどの機能をワンタッチで開くことができる。
指令 3 则#
ここで正式に iPhone からブログを発信するための 3 つのショートカットを共有する。必要なアプリは、標準のショートカット(shortcuts)とフォトライブラリに加えて、markdown エディタTaioが必要で、サブスクリプションは不要だ(もしメモ帳を使って markdown を書くつもりなら、Taio もインストールする必要はない)。
新しい markdown を作成する#
効率を追求する精神で、ファイルを作成するのは手動ではなく、以下の 5 ステップで簡単に行える:
- ファイル名を尋ねる
- ファイルテンプレートを準備する
- Taio を使ってファイルを作成する(他の編集ツールに置き換えても良い)
- url をデコードする(このステップは必ずメモしておく必要がある。バグなのかどうかは分からないが、デコードせずに url をそのまま使うと、最初のステップで取得したファイル名を url に入れることができないと表示される。なぜか不思議だ。ファイル名は明らかにテキストで、しかも英語なのに、なぜダメなのか)
- デコードした url を使って Taio で作成したばかりのファイルを開き、情報を補完して直接書き始めることができる
markdown をアップロードする#
- 入力元は share sheet、つまり共有機能(右上のオプションで share sheet に表示するオプションを選択する必要がある)
- 公開インターフェースのアドレスを入力する
Get contents of URL
は実際には ajax リクエストを送信するもので、データは自分で決定する。私は現在の時間、ファイル内容、ファイルパスの 3 つのデータを使用した- 最後にインターフェースの返結果を表示する。このステップは省略可能だ。リクエストがエラーになると、前のステップで停止して警告が表示される
実際には、アップロード時に記事情報の日付を動的に変更して、記事の更新時間をリフレッシュすることもできる。少し正規表現の知識を使えば可能だ。
画像をアップロードする#
誰かが「画像はどうするの?」と尋ねるかもしれないが、上記の知識を持っていれば、これは簡単だ。
PC では PicGo と jsdelivr を使って画像をホスティングすることが一般的だが、iOS でも同様だ。上記でファイルを送信する原理を説明したので、このインターフェースを使って画像を送信するのも全く問題ない。createBlob
の時に base64 を選択すれば良い。
プロセスは以下の通り:
- フォトライブラリから画像を選択する
- ファイル名を尋ねる
- jpg に圧縮する(圧縮しないとファイルが非常に大きくなり、heic ファイルは一部のアプリで開けない可能性がある?)
- jpg を base64 に変換してインターフェースに送信する
- 公開インターフェースのアドレスを入力する
- base64 を公開し、blob を作成する際に encoding を base64 に設定することを忘れない
- インターフェースの返結果を表示する
Android はどうか#
Android を使っている時には、この問題を考えたことはなかったが、Shortcut Makerが一部の機能を実現できるようだ。しかし、他のアプリとの連携の自由度は制限されると思われる。
または直接github.devを使うこともできるが、欠点は科学的にインターネットを利用する必要があり、編集エリアが少し狭いことだ。
最後に#
実際、私はこれが単なる遊びであり、将来的には語雀のように役に立たない可能性があることを理解している。
直接スマートフォンで更新するシーンは本当に多いのだろうか?スマートフォンで長文を書く需要は確かに少ないが、短い文章を書く場合には「ブログ」を発信する必要はないと思う。せいぜい「微博」程度だ。
では、この静的ブログに微博機能を追加するべきか(実際、多くの個人ブログにこの機能があるのを見かける)?機能を実現するのは簡単だが、静的ページで一言発信するために毎回ビルドを行うコストパフォーマンスが低いと感じる。新浪微博のページを直接埋め込んでしまう方が良いのだろうか?
同様に、画像を共有する問題もある。この静的ブログの画像エリアは何百年も更新されていない。更新体験が少し欠けていると感じ、画像とテキストの連動が不足している。別の画像ホスティングサービスを探すべきだろうか?そのためにFlickrと500pxに登録したが、無料ユーザーはアップロードできる画像数に制限がある。実際にはその制限を使い切ることはないかもしれないが、束縛を感じる。最も完璧な選択肢である Instagram にも唯一の致命的な欠点があり、科学的にインターネットを利用する必要がある。ああ、辛い。
もう少し時間をかけて考えてみよう。以前は自分のコメントシステムを使いたいと思っていたが、今は第三者の方が便利かもしれないと思うようになった。以前は画像を同じプロジェクトに集中させて管理する方が便利だと思っていたが、今はパッケージ化するのに時間を浪費するよりも画像ホスティングサービスを使った方が良いと感じている。今はブログに微博を追加したり、画像を他のコミュニティに置いたりしたいと思っているが、将来的には本当に打ちのめされることはないのだろうか?本当に分からない。プロダクトマネージャーのニーズが常に変わると批判しているが、実際には自分自身がこんなに変わりやすいのだ。