GitHub Pagesにアップロードされたページから投稿できる。
成果物
手順
事前準備
手順
- DEMOにアクセスする
- 自分のハンドルを入力する(
ytyaru.bsky.social
等) - アプリパスワードを入力する(
1234-abcd-5678-efgh
等) - 投稿内容を入力する(300字以内)
投稿
ボタンを押す- 自分のハンドルのリンクをクリックする
- 自分のBlueSkyプロフィールサイトに行くので投稿されたか確認する
技術情報
実装するにあたり次の情報が必要だった。
- ローカルサーバ
- OGP
- BlueSky API
ローカルサーバ
OGP (OpenGraph Protocol)
BlueSkyでリンクカードを表示する時のメタデータをHTMLに設定する。その書式はOGPで定義されている。
<head prefix="og: https://ogp.me/ns#"> <meta property="og:type" content="article"> <meta property="og:title" content="BlueSky APIで投稿する"> <meta property="og:description" content="JavaScriptでAPIを叩くページを作り、GitHub Pagesにアップロードした。"> <meta property="og:url" content="https://ytyaru.github.io/JS.BlueSky.API.post.20250805153030/2/index.html"> <meta property="og:site_name" content="GitHub Pages"> <meta property="og:image" content="https://github.com/ytyaru/JS.BlueSky.API.post.20250805153030/blob/master/docs/asset/image/bsky-post-page.png?raw=true"> ... <head>
BlueSky API
以下を参考にした。
日本語の情報を探していたが、なぜかGAS(Google Apps Script)上の情報ばかりだった。
このGASは専用APIを使っているので、これをJavaScript APIに置換する作業が面倒だった。
bluesky.js
BlueSky API部分はbluesky.jsにまとめた。以下抜粋。
class BlueSky { constructor(){this._={}} set handle(v) {if (Type.isStr(v) && 0 < v.length){this._.handle=v}} set appPw(v) {if (Type.isStr(v) && 0 < v.length){this._.appPw=v}} async #createSession() { const res = await fetch('https://bsky.social/xrpc/com.atproto.server.createSession', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ identifier: this._.handle, password: this._.appPw }) }); if (200===res.status) { const json = await res.json(); const sessionData = json; console.log('✅ Blueskyログイン成功!'); return sessionData.accessJwt; } else {throw new Error(`ログイン失敗`, res);} } async post(message) { try { const accessJwt = await this.#createSession(); const res = await fetch('https://bsky.social/xrpc/com.atproto.repo.createRecord', { method: 'POST', headers: { 'Authorization': `Bearer ${accessJwt}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ repo: this._.handle, collection: 'app.bsky.feed.post', record: { text: message, createdAt: new Date().toISOString() } }) }); return 200 === res.status; } catch (error) { console.error('❌ 投稿エラー:', error); return false; } } }
ようするに以下2つのAPIを叩いている。
概要 | API |
---|---|
アクセストークン取得する | https://bsky.social/xrpc/com.atproto.server.createSessionDoc createSession |
投稿する | https://bsky.social/xrpc/com.atproto.repo.createRecordDoc createRecord |
ただこれ、公式サイトのログイン専用ページでないから行儀が悪い。
OAuth2認証
サードパーティ製サイトで安全にログインするためには公式サイトが提供する認証ページとやり取りする方法がある。
- 自作サイトで認証用ページURLをリクエストする
- ユーザは認証用ページでパスワードを入力するから自作サイトで無断収集されず安全
- 自作サイト側では2の応答結果としてアクセストークンをもらう
- アクセストークンをHTTPヘッダに付与して投稿APIを叩く
ログイン認証ページでユーザ名とパスワードを入力するのだが、それは公式サイトのページだから安全が保証されている。自作サイトでそのページをリクエストすれば安全に認証できる。
認証用ページからレスポンスが帰ってくるとURLパラメータとしてアクセストークンが付いてくるから、それをHTTPヘッダに付与してPOSTして投稿する。
デモ
https://ytyaru.github.io/Html.Mastodon.Account.Info.20220611094830/
リポジトリ
https://github.com/ytyaru/Html.Mastodon.Account.Info.20220611094830
認証用ページにリクエストするコード部分
BlueSkyではどうOAuth認証するか不明
ググったけど分からなかった。いつかまた調査したい。