2024-04-23 13:21:26 +00:00
|
|
|
+++
|
|
|
|
date = "2024-04-12"
|
|
|
|
tags = ["bluesky", "atproto"]
|
|
|
|
title = "blueskyのcustom feedでslash cmdを有効にした"
|
|
|
|
slug = "bluesky"
|
|
|
|
+++
|
|
|
|
|
|
|
|
blueskyでfeed serverを立て、slash command(cmd slash)を有効にしました。
|
|
|
|
|
2024-04-23 13:28:33 +00:00
|
|
|
- https://github.com/bluesky-social/feed-generator
|
2024-04-23 13:21:26 +00:00
|
|
|
|
|
|
|
```sh
|
|
|
|
/help
|
|
|
|
|
|
|
|
or
|
|
|
|
|
|
|
|
@yui.syui.ai /help
|
|
|
|
```
|
|
|
|
|
2024-04-23 13:28:33 +00:00
|
|
|
> スラッシュ コマンドを使用すると、テーブル、タスクリスト、コード ブロックなど、より複雑な Markdown を簡単に入力できます。
|
|
|
|
|
|
|
|
- https://api.slack.com/interactivity/slash-commands
|
|
|
|
- https://docs.github.com/issues/tracking-your-work-with-issues/about-slash-commands
|
|
|
|
|
|
|
|
これによって何ができるのかというと、例えば、`/help`と投稿すると、botが反応できるようになります。
|
|
|
|
|
2024-04-23 13:21:26 +00:00
|
|
|
今までのbotは大体が(1)mention, replyで反応するか、(2)feed(following)から反応するか、(3)global timelineから反応するかの方法があり、それぞれに欠点がありました。
|
|
|
|
|
|
|
|
- 1. mention, reply : 最も合理的で負荷が少なくlimitに引っかかる可能性は少なく確実な方法。ただ、ユーザーからすると面倒
|
|
|
|
- 2. feed(following) : user timelineから取るので負荷も少ない。ただ、followingの処理が必要になったり、follow listの監視と解除があればその処理が必要
|
|
|
|
- 3. global timeline : ユーザーが増えるにつれて流速が早くなり負荷が高くなる。全部に対応するのが難しくなるかも
|
|
|
|
|
|
|
|
しかし、feed serverを自分で建て、そこから反応すると、このようなデメリットを解消できます。これは`custom feed`と呼ばれるものになります。
|
|
|
|
|
|
|
|
ちなみに、[skyfeed](https://skyfeed.app/)で簡単に作れますが、自前でhostするのがいいです。`skyfeed`だと反応が遅くなってしまう。
|
|
|
|
|
|
|
|
feed server自体は、昔に`feed.syu.is`のほうで建てていて、今回はそれを`bsky.network`にdeply(登録)し、didを`bsky.social`のaccountに変更したのと、algosの正規表現を調整しました。
|
|
|
|
|
|
|
|
- [bsky.app](https://bsky.app/profile/did:plc:4hqjfn7m6n5hno3doamuhgef/feed/cmd)
|
|
|
|
- [app.bsky.feed.getFeedSkeleton](https://feed.syu.is/xrpc/app.bsky.feed.getFeedSkeleton?feed=at://did:plc:4hqjfn7m6n5hno3doamuhgef/app.bsky.feed.generator/cmd)
|
|
|
|
|
|
|
|
```sh
|
|
|
|
$ git clone https://github.com/bluesky-social/feed-generator
|
|
|
|
$ cd feed-generator
|
|
|
|
├── .env
|
|
|
|
└── src
|
|
|
|
├── scripts
|
|
|
|
│ └── publishFeedGen.ts
|
|
|
|
├── algos
|
|
|
|
│ ├── cmd.ts
|
|
|
|
│ └── index.ts
|
|
|
|
└── subscription.ts
|
|
|
|
```
|
|
|
|
|
|
|
|
編集するのは上に挙げたファイルです。
|
|
|
|
|
|
|
|
```sh
|
|
|
|
FEEDGEN_PORT=3000
|
|
|
|
FEEDGEN_LISTENHOST="0.0.0.0"
|
|
|
|
FEEDGEN_SQLITE_LOCATION="/data/db.sqlite"
|
|
|
|
FEEDGEN_HOSTNAME="feed.syu.is"
|
|
|
|
FEEDGEN_SUBSCRIPTION_RECONNECT_DELAY=3000
|
|
|
|
FEEDGEN_PUBLISHER_DID=did:plc:4hqjfn7m6n5hno3doamuhgef
|
|
|
|
FEEDGEN_SUBSCRIPTION_ENDPOINT="wss://bsky.network"
|
|
|
|
```
|
|
|
|
|
2024-04-23 13:28:33 +00:00
|
|
|
```ts:scripts/publishFeedGen.ts
|
|
|
|
const handle = ''
|
|
|
|
const password = ''
|
|
|
|
const recordName = ''
|
|
|
|
const displayName = ''
|
|
|
|
const description = ''
|
|
|
|
const avatar: string = 'icon/ai.png'
|
|
|
|
```
|
|
|
|
|
|
|
|
```sh
|
|
|
|
./feed-generator
|
|
|
|
├── icon/ai.png
|
|
|
|
├── .env
|
|
|
|
└── src
|
|
|
|
```
|
|
|
|
|
|
|
|
```sh
|
|
|
|
# bsky.networkにpush
|
|
|
|
$ npm run publishFeed
|
|
|
|
```
|
|
|
|
|
2024-04-23 13:21:26 +00:00
|
|
|
```ts:src/subscription.ts
|
|
|
|
.filter((create) => {
|
|
|
|
return create.record.text.match('^/[a-z]') || create.record.text.match('^@ai');
|
|
|
|
//return create.record.text.toLowerCase().includes('alf')
|
|
|
|
})
|
|
|
|
```
|
|
|
|
|
|
|
|
```sh
|
|
|
|
$ docker compose build feed-generator
|
|
|
|
$ docker compose up feed-generator
|
|
|
|
```
|
|
|
|
|
|
|
|
これを`bot`で取得すると、返信できます。
|
|
|
|
|
|
|
|
> feed = at://did:plc:4hqjfn7m6n5hno3doamuhgef/app.bsky.feed.generator/cmd
|
|
|
|
|
|
|
|
```rust:src/feed_get.rs
|
|
|
|
// https://docs.bsky.app/docs/api/app-bsky-feed-get-feed
|
|
|
|
extern crate reqwest;
|
|
|
|
use crate::data_refresh;
|
|
|
|
use crate::url;
|
|
|
|
|
|
|
|
pub async fn get_request(feed: String) -> String {
|
|
|
|
let token = data_refresh(&"access");
|
|
|
|
let url = url(&"feed_get");
|
|
|
|
let feed = feed.to_string();
|
|
|
|
|
|
|
|
let client = reqwest::Client::new();
|
|
|
|
let res = client
|
|
|
|
.get(url)
|
|
|
|
.query(&[("feed", feed)])
|
|
|
|
.header("Authorization", "Bearer ".to_owned() + &token)
|
|
|
|
.send()
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
let status_ref = res.error_for_status_ref();
|
|
|
|
|
|
|
|
match status_ref {
|
|
|
|
Ok(_) => {
|
|
|
|
return res.text().await.unwrap();
|
|
|
|
}
|
|
|
|
Err(_e) => {
|
|
|
|
let e = "err".to_string();
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|