LoginSignup
2
1

vxtwitterに自動で変換するBot

Last updated at Posted at 2024-01-04

TL;DR

x.comで始まるリンクを読み取るとvxtwitter.comに変換してくれるDiscord Botを作ったよ
ホスティングはshuttleでやったよ

作成経緯

Twitterが色々変更されていく中で、Discordでリンクを自動で展開する機能がなくなった(埋め込み)
ので、埋め込みを表示してくれるリダイレクトのリンクができた(fxtwitter fixupとか)
でもわざわざ打ち直すの面倒
→Botにしようぜ

機能

イベントハンドラ

Messageにリンクが含まれていたら、

  • Bot でない
  • 正規表現にマッチする文字列が存在するか

を判定する。

それらが通った場合、マッチした条件にあう文字列を使ってhttp://vxtwitter.comのリンクに加工して、そのメッセージにリプを返す

EventHandler::message
#[async_trait]
impl EventHandler for Bot {
    async fn message(&self, _ctx: Context, msg: Message) {
        if msg.author.bot {
            return;
        }

        let Some((username, hash)) = match_url(&msg.content) else {
            return;
        };
        let reply = format!("https://vxtwitter.com/{}/status/{}\n", username, hash);
        check_msg(msg.reply(&_ctx.http, reply).await);
    }

    async fn ready(&self, _: Context, ready: Ready) {
        info!("{} is connected!", ready.user.name);
    }
}

正規表現で必要なパラメータを抽出する

正規表現をすると厳密に必要なパラメータを取り出せる(ただしセンスがいる)

match_url
// 正規表現マッチングを行う関数
fn match_url(content: &str) -> Option<(String, String)> {
    let regex = Regex::new(
        r"https:\/\/(x|twitter)\.com\/(?<username>[a-zA-Z0-9_]{1,16})\/status\/(?<hash>[0-9]+)",
    )
    .unwrap();

    regex
        .captures(content)
        .map(|caps| (caps["username"].to_string(), caps["hash"].to_string()))
}

部分的なマッチパターンの前に?<hoge>とやるとあとで同じ文字列をキーにしてマッチした値を取得できる
今回だと?<username> ?<hash>が該当する

Shuttleのセットアップ

Shuttleでアカウント作って(GitHubで連携すると楽) NewProjectで出てくるコマンドを打つ

cargo install cargo-shuttle
cargo shuttle init   # 対話型のやりとりで設定できる(使用するフレームワークを聞かれたときに今回はSerenityを選択する)
cargo shuttle run    # ローカル実行
cargo shuttle deploy # shuttle.rsのPJにデプロイできる

新規PJで始めることをおすすめします。既存のレポのディレクトリを指定するとうまくインストールされなかったりデプロイに失敗します1

機密変数について

今回扱うDiscord BotではDISCORD_TOKENが該当する
これを生成されるSecrets.tomlDISCORD_TOKEN="Your secret discrod token"のように記入する
また、.gitignoreSecrets.tomlを追加すること(ドキュメントにもこう書いてあるんだけど、なぜ最初から追加されていないかは謎)

Discord Botの作成について

Applicationsでアプリ作って権限設定してBotの欄でTokenをコピーしてSecrets.tomlに貼る。
詳しくは下記参考にしてください。

Botの作成方法はほとんど変わりませんが、3年以上前の記事のためすべてを参考にせず SerenityのドキュメントやShuttleでのチュートリアルを必ず参照してください。

Shuttleのアイドリングについて

デプロイとかもろもろしているとこんなログが出ます

PS C:\Users\raiga\dev> cargo shuttle init
What do you want to name your project?
It will be hosted at ${project_name}.shuttleapp.rs, so choose something unique!
✔ Project name · <hoge>

Where should we create this project?
✔ Directory · <huga>

Shuttle works with a range of web frameworks. Which one do you want to use?
✔ Framework · serenity

Creating project "vxbot" in "C:\Users\raiga\dev\<huga>"

Hint: Check the examples repo for a full list of templates:
      https://github.com/shuttle-hq/shuttle-examples
Hint: You can also use `cargo shuttle init --from` to clone templates.
      See https://docs.shuttle.rs/getting-started/shuttle-commands
      or run `cargo shuttle init --help`

✔ Claim the project name "<hoge>" by starting a project container on Shuttle? · yes

Project "<hoge>" is ready
Your project will sleep if it is idle for 30 minutes. ### <- ここ!!!!!!!!!!
To change the idle time refer to the docs: https://docs.shuttle.rs/getting-started/idle-projects

Your project will sleep if it is idle for 30 minutes.
ドキュメントには、「2 calls/minないとスリープするよ。スリープ状態の復帰はCLIからでしかできないよ」みたいなことが書いてある。Botに関してはこの仕様はつらいので、設定し直す必要がある。

cargo shuttle project restart --idle-minutes 0とするとスリープしないようにできる。これはドキュメントでも言及されているので問題無し。
念のため、statusコマンドでアイドル時間が0なことを確認する。

PS C:\Users\raiga\dev\vxbot_shuttle> cargo shuttle project status
Project "vxbot" is ready
Idle minutes: 0 # きちんと設定されている

動作例

image.png

Repo

最後に

Discordで高専生を中心としたメンバーが楽しくやっています。

  1. そもそも既存のSerenityBotだと#[shuttle_runtime::main]とか#[shuttle_secrets::Secrets] secret_store: SecretStore,みたいなShuttle特有の書き方を反映するのが少し大変。今回は小規模なPJだから1時間ほど溶かすにとどまりましたが、大規模なアプリの場合(データベースとかあったりすると)移行がかなり大変かも(そういった移行がし易いように設計しろという話は尤もすぎる)

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1