X

X(Twitter)Post(Tweet)をDiscordに貼ってもOGPが表示されなくなって久しい。

最近ではfxtwitterやvxtwitter等のサービスが出てきており、リンクをコピーしてprefixにfxとかvxとか付けて共有する。みたいな流れになっている。

が、面倒なので自動化するBotを作った。

Serenity

RustにはDiscordのBotを作れるserenityというcrateがあり、題材として勉強にぴったりだったので作ってみた。

fxtd

mainではClientを作成し、startするだけ

let mut client = Client::builder(config.token, intents)
    .event_handler(Handler)
    .await
    .with_context(|| {
        error!("Failed to create client");
        "Failed to create client"
    })?;

client.start().await.with_context(|| {
    error!("Failed to start client");
    "Failed to start client"
})

メッセージの投稿やスレッドの作成など、それぞれのイベントに対してハンドラーを書くといい感じに処理してくれる。

今回はメッセージにtwitter.comx.comが含まれていたら置換し、スレッドが作成されたら自動で参加するようにした。

#[async_trait]
impl EventHandler for Handler {
    async fn message(&self, ctx: Context, msg: Message) {
        twitter(&ctx, &msg).await;
    }

    async fn thread_create(&self, ctx: Context, thread: GuildChannel) {
        if let Err(why) = thread.id.join_thread(&ctx.http).await {
            error!("Error joining thread: {:?}", why);
        }
    }

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

async fn twitter(ctx: &Context, msg: &Message) {
    let url_regex =
        Regex::new(r"https?://(twitter.com|x.com)/[a-zA-Z0-9_]+/status/[0-9]+").unwrap();
    for url in url_regex.find_iter(&msg.content) {
        let host_regex = Regex::new(r"https?://(twitter.com|x.com)").unwrap();
        let new_url = host_regex.replace(url.as_str(), "https://fxtwitter.com");
        match msg.channel_id.say(&ctx.http, &new_url).await {
            Ok(_) => info!("Sent new link: {}", new_url),
            Err(why) => error!("Error sending message: {:?}", why),
        }
    }
}

これだけでちゃんと動いてくれるし、かなり早いので便利。

自宅の余ったマシンで動かしています。

総括

他にも機能が優れたBotがあるので、別にこだわりがなければそっちでいいと思います。FixTweetとか。

あとDiscordのモバイルアプリ、新しくなってからUI云々以前に普通に動作が不安定な気がする。頼むよ〜

おわりに

この記事はn01e0 Advent Calendar 2023の11日目の記事です。

明日はあるかわかりません

また、IPFactory OB Advent Calendar 2023の11日目の記事も兼ねています。