XENEXE

Bluesky API と Google Apps Script (GAS) でポストを投稿・取得・削除する


heroImage

1. はじめに

2024年02月06日、Bluesky の招待制度を解除されたので、筆者もアカウントを作成しました。新しいサービスを使い始めたら、まずは API 周りを調査しないといけません。本記事では、 Bluesky API について調査した結果と、Bluesky API を GAS で叩いて遊んだ結果をまとめたものになります。Bluesky API に関しては公式ドキュメント 1 が公開されているので、詳しい仕様については、そちらを参照ください。

2. ポストを投稿する

Bluesky API 経由でポストを投稿する方法は簡単で、com.atproto.server.createSession を叩いて認証セッションを作成して、com.atproto.repo.createRecord を叩いてポストを投稿します。

以下のサンプルコードを実行する際は、[USER_IDENTIFIER][APP_PASSWORD] を変更した後、main 関数を実行します。[USER_IDENTIFIER] は、登録済みのメールアドレスまたは Handle (xxx.bsky.social) を設定してください。また、[APP_PASSWORD] にアカウント登録時のパスワードを設定するのは非推奨です。

1
function main() {
2
createRecord('テストポスト')
3
}
4
5
// https://www.docs.bsky.app/docs/api/com-atproto-server-create-session
6
function createSession() {
7
const url = 'https://bsky.social/xrpc/com.atproto.server.createSession'
8
9
const payload = {
10
identifier: '[USER_IDENTIFIER]',
11
password: '[APP_PASSWORD]',
12
}
13
14
const options = {
15
method: 'post',
16
headers: {
17
'Content-Type': 'application/json; charset=UTF-8',
18
},
19
payload: JSON.stringify(payload),
20
}
21
22
const response = UrlFetchApp.fetch(url, options)
23
return JSON.parse(response.getContentText())
24
}
25
26
// https://www.docs.bsky.app/docs/api/com-atproto-repo-create-record
27
function createRecord(msg) {
28
const url = 'https://bsky.social/xrpc/com.atproto.repo.createRecord'
29
30
const payload = {
31
repo: createSession().handle,
32
collection: 'app.bsky.feed.post',
33
record: {
34
text: msg,
35
createdAt: new Date().toISOString(),
36
},
37
}
38
39
const options = {
40
method: 'post',
41
headers: {
42
'Content-Type': 'application/json',
43
Authorization: 'Bearer ' + createSession().accessJwt,
44
},
45
payload: JSON.stringify(payload),
46
}
47
48
UrlFetchApp.fetch(url, options)
49
}

3. 自分のポストを取得する

Bluesky API 経由で自分のポストを取得する方法は簡単で、com.atproto.server.createSession を叩いて認証セッションを作成して、app.bsky.feed.getAuthorFeed を叩いて自分のポストを取得します。デフォルトでは最新のポスト、50 件が取得される仕様です。取得件数を変動させたり古いポストを取得するには、limitcursor を変更します。詳しくは公式のドキュメントを参照ください。

以下のサンプルコードを実行する際は、[USER_IDENTIFIER][APP_PASSWORD] を変更した後、main 関数を実行します。[USER_IDENTIFIER] は、登録済みのメールアドレスまたは Handle (xxx.bsky.social) を設定してください。また、[APP_PASSWORD] にアカウント登録時のパスワードを設定するのは非推奨です。

1
function main() {
2
getAuthorFeed().feed.map((x) => console.log(x))
3
}
4
5
// https://www.docs.bsky.app/docs/api/com-atproto-server-create-session
6
function createSession() {
7
const url = 'https://bsky.social/xrpc/com.atproto.server.createSession'
8
9
const payload = {
10
identifier: '[USER_IDENTIFIER]',
11
password: '[APP_PASSWORD]',
12
}
13
14
const options = {
15
method: 'post',
16
headers: {
17
'Content-Type': 'application/json; charset=UTF-8',
18
},
19
payload: JSON.stringify(payload),
20
}
21
22
const response = UrlFetchApp.fetch(url, options)
23
return JSON.parse(response.getContentText())
24
}
25
26
// https://www.docs.bsky.app/docs/api/app-bsky-feed-get-author-feed
27
function getAuthorFeed() {
28
const url = `https://bsky.social/xrpc/app.bsky.feed.getAuthorFeed?actor=${createSession().handle}`
29
30
const options = {
31
method: 'GET',
32
headers: {
33
Authorization: 'Bearer ' + createSession().accessJwt,
34
},
35
}
36
37
const response = UrlFetchApp.fetch(url, options)
38
return JSON.parse(response.getContentText())
39
}

4. 自分のポストを削除する

Bluesky API 経由で自分のポストを削除する場合、ポストの Record Key を取得する必要があります。Record Key は、Bluesky の Web クライアントで確認することが出来ます。任意のポストを Bluesky の Web クライアントで表示させると、URL として https://bsky.app/profile/xxx.bsky.social/post/3kksx5ddx6d24 などと表示されます。この 3kksx5ddx6d24 が Record Key にあたります。

以下のサンプルコードは、上記で示した getAuthorFeed 関数を利用して、最新ポストの Record Key を取得し、削除するものです。正常に実行されると、自分の最新ポストが削除されるので注意してください。

以下のサンプルコードを実行する際は、[USER_IDENTIFIER][APP_PASSWORD] を変更した後、main 関数を実行します。[USER_IDENTIFIER] は、登録済みのメールアドレスまたは Handle (xxx.bsky.social) を設定してください。また、[APP_PASSWORD] にアカウント登録時のパスワードを設定するのは非推奨です。

1
function main() {
2
const rkey = getAuthorFeed().feed.shift().post.uri.split('/').pop()
3
deleteRecord(rkey)
4
}
5
6
// https://www.docs.bsky.app/docs/api/com-atproto-server-create-session
7
function createSession() {
8
const url = 'https://bsky.social/xrpc/com.atproto.server.createSession'
9
10
const payload = {
11
identifier: '[USER_IDENTIFIER]',
12
password: '[APP_PASSWORD]',
13
}
14
15
const options = {
16
method: 'post',
17
headers: {
18
'Content-Type': 'application/json; charset=UTF-8',
19
},
20
payload: JSON.stringify(payload),
21
}
22
23
const response = UrlFetchApp.fetch(url, options)
24
return JSON.parse(response.getContentText())
25
}
26
27
// https://www.docs.bsky.app/docs/api/app-bsky-feed-get-author-feed
28
function getAuthorFeed() {
29
const url = `https://bsky.social/xrpc/app.bsky.feed.getAuthorFeed?actor=${createSession().handle}`
30
31
const options = {
32
method: 'GET',
33
headers: {
34
Authorization: 'Bearer ' + createSession().accessJwt,
35
},
36
}
37
38
const response = UrlFetchApp.fetch(url, options)
39
return JSON.parse(response.getContentText())
40
}
41
42
// https://www.docs.bsky.app/docs/api/com-atproto-repo-delete-record
43
function deleteRecord(rkey) {
44
const url = 'https://bsky.social/xrpc/com.atproto.repo.deleteRecord'
45
46
const payload = {
47
repo: createSession().handle,
48
collection: 'app.bsky.feed.post',
49
rkey: rkey,
50
}
51
52
const options = {
53
method: 'post',
54
headers: {
55
'Content-Type': 'application/json',
56
Authorization: 'Bearer ' + createSession().accessJwt,
57
},
58
payload: JSON.stringify(payload),
59
}
60
61
UrlFetchApp.fetch(url, options)
62
}

5. おわりに

執筆時点では、招待制度を解除されてユーザーが増えた影響か、結構 API の使用制限 (RateLimitExceeded) に引っかかります。一応、GitHub Discussions 2 では 3000 リクエスト / 5 分 に設定されているそうですが、一時的に厳しくなっている可能性もありますね。Bluesky 自体が開発途上なので、API 周りのおいおい整備されていくと思います。いつまで無料で遊べるかもわからないので、今のうちに遊んでおこうと思います。


  1. Bluesky, Get Started:https://www.docs.bsky.app/docs/get-started

  2. GitHub Discussions, Are there rate limits for the API?:https://github.com/bluesky-social/atproto/discussions/697