ObsidianからGhostへ直接投稿するツールを自作した話

※本記事は広告を含みます

筆者は最近Obsidianで記事執筆を行うことが多くなっています。
んで、Obsidianで書いた記事をGhostブログに投稿する際、毎回ブラウザを開いてコピペするのが面倒だったので、Pythonで専用の投稿ツールを作ってみました。
今回は開発する際のあれこれをここで共有していきたいと思います。

開発の動機

正直なところ興味本位というのが強いのですが、一応「ブログ投稿の手間をより少なくする、という目的があります。

  • 現状: Obsidianで書く -> ブラウザでGhost管理画面を開く -> 新規投稿 -> コピペ -> 設定入力 -> 公開
  • 理想: Obsidianで書く -> ツール起動 -> ファイル選択 -> 投稿ボタン一発

この「理想」を実現するため、PythonからGhostのAdmin APIを叩くシンプルなツールとして設計することに。

なお、Ghostの記事(Posts)APIは画像データのアップロードは行えません。なので、「画像が必要な投稿には対応しない!」と割り切ることにしました。まあこのブログは基本的にテキストオンリーなので、これで充分でしょう!

ちなみに、Ghostには画像アップロードのAPIも用意されているみたいなので、先に記事内の画像をアップロード → 記事内の画像をURLに変換し、記事を登録、みたいなことができそうではあります。そのうちやるかも。

技術スタック

  • 言語: Python 3.x
  • GUI: tkinter (標準ライブラリ)
  • 認証: PyJWT (Ghost Admin APIのJWT生成用)

構成は非常にシンプル。Markdownファイルを読み込み、Frontmatter(YAMLヘッダ)からタイトルやタグを自動抽出し、APIにPOSTするだけです。

プログラムはAntigravityにお願い

今回も、個人的なトレンドであるAntigravityにお願いしてツールを作成してもらいます。ツールでやりたいことが明確であり、仕様もシンプルだからか、1分かからずに動く状態のものが完成しました。早すぎて草。
ちなみに筆者がAntigravityを利用している理由は、Geminiの有料勢だからです。以前はClaude Codeも使ったりしていましたが、シンプルに金銭面がキツい!てことで、利用するAIはGeminiに絞ってます。一応都心で仕事しているエンジニアなのにも関わらず、なんとひもじいことか。。

直面した壁

なんとなく予想はしていましたが、ちゃんとネットワーク依存でエラーになりました。
この手のAPIの疎通ではなかなか1発で通ることはないですからね。しょうがないね。

犯人はCloudflare WAF

今回引っかかったのはここでした。
ローカルで実装し、いざ投稿ボタンを押してみると。。

Error: 403 Forbidden

権限エラーっぽいですね。この403は初期構築時や、今回みたいな疎通時にはよく見るやつです。嫌いになりそうですね!

返ってきたレスポンスを見ると、Ghostのサーバーではなく、手前にある Cloudflare がブロックしているもよう。そういえばGhostを立ち上げた際に、CloudflareのWAFルールで、APIのエンドポイントをひっかけるようにしていました。うっかり。
ってことで、ここをなんとかして突破するように改善していきます。

User-Agentをホワイトリスト化する

サーバー(Cloudflare)側の設定を確認・変更できる環境なので、「正攻法」 で行くことにしました。

  1. ツール側のUser-Agentを固有のものに設定。
    headers = {
        'Authorization': f'Ghost {token}',
        'User-Agent': 'hogehogeAgent'  # ここをツール専用のものにする
    }
    
  2. CloudflareのWAFルールで、このUser-Agentを 許可(Allow / Skip) する設定を追加。
http.user_agent eq "hogehogeAgent/1.0"

これにより、無事にブロックを回避し、API経由での投稿に成功しました!
なお、今回の対応だとUser-Agentが外に漏れてしまった場合、Cloudflareを突破してしまう可能性があります。しかし、Ghost側でAPIキーによる認証が行われるので、最後の砦まで突破されることはそうそうないんじゃないかなって思ってます。知らんけど。

できたもの

こんな感じのものができました。
恐らく、UIを見ればなんとなく何ができるのかは分かるかと思います!
通常ポストならこれで充分でしょう。たぶん。

Pasted image 20260215205349.png

まとめ

  • Pythonはこういうツール作るのにちょうどいい
  • これで執筆フローが爆速になった!
  • まだまだいろいろ遊べそう!