🍜

【Discord bot】画像検索コマンドの実装

2022/02/17に公開

ソースコード

完成系はこんな感じ
スクリーンショット
きっかけはRust製コンパイラを使ってみたくなり、何かいい題材がないかと敷居の低いdiscord botを作成してみました。

環境

  • node: v16.14.0
  • typescript: v4.5.5
  • discord.js: v13.6.0

SWCを導入する

yarn add -D @swc/cli @swc/core
.swcrc
{
  "module": {
    "type": "commonjs"
  },
  "minify": true,
  "jsc": {
    "minify": {
      "compress": true
    },
    "parser": {
      "syntax": "typescript",
      "tsx": false
    },
    "target": "es2021",
    "baseUrl": "src",
    "paths": {
      "~/*": ["./*"]
    }
  }
}

筆者はESModules向けのパッケージ構築に失敗したので知見ある方はコメントで構成のアドバイス等いただけると助かります。
.swcrcの構成は必要最低限で、極力tsconfigの内容とあわせると良いと思います。
https://swc.rs/docs/configuration/swcrc

"build": "npx swc src -d dist --config-file .swcrc",

余談ですが、最近concurrentlyを使ったformatコマンドの構成を知りました👀

"format": "concurrently 'yarn:format:*'",
"format:eslint": "eslint ./src --fix",
"format:prettier": "prettier ./src --write",

画像検索機能の追加

今回はGoogleCustomSearchAPIを使用します。環境構築については他の方々がわかりやすい記事を公開されているので省略。
https://blog.wackwack.net/entry/2017/12/26/211044

@discordjs/buildersから提供されているSlashCommandBuilderで以下のようなコマンドを作成する。

export const commandName = "search";
export const command = new SlashCommandBuilder()
  .setName(commandName)
  .setDescription("画像検索してくれるよ!")
  .addStringOption((option) =>
    option.setName("keyword").setDescription("キーワード").setRequired(true)
  )
  .addIntegerOption((option) =>
    option
      .setName("save")
      .setDescription("メッセージを残しますか?")
      .setChoices([
        ["残す", 1],
        ["削除", 0],
      ])
  );

検索機の実装。今回は最低限のクエリのみを実装していますが追加でフィールドを設定できます。
https://developers.google.com/custom-search/v1/reference/rest/v1/cse/list

const search = async (q) => {
  const endpoint = new URL("https://www.googleapis.com/customsearch/v1");
  endpoint.searchParams.append("key", process.env.SEARCH_KEY as string);
  endpoint.searchParams.append("cx", process.env.SEARCH_CX as string);
  endpoint.searchParams.append("searchType", "image");
  endpoint.searchParams.append("q", q);
  const response = await axios({
    method: "get",
    url: endpoint.toString(),
  });
  const item = response.data.items[0];
  return item && [item.link, item.image.thumbnailLink];
};

discord botではリッチなメッセージを送ることができるのでMessageEmbedを使用してメッセージを整形します。

const embed = new MessageEmbed()
  .setImage(url ?? "")
  .setTitle(`検索キーワード: ${q}`)
  .setThumbnail(thumbnail ?? "")
  .setDescription(url ?? "");
const message = await stream.channel?.send({
  content: `${stream.member?.toString()}\n以下の画像が見つかりました🧑‍💻`,
  embeds: [embed],
});

まとめ

一時間もかからずにdiscord botを作成することができました。SWCも非常に早く満足です。他のトランスパイラーとベンチマークの比較ができれば追記していこうと思います。

これを機にSWCとESLint,Prettierのスポンサーシップに登録してみました🎉
https://github.com/tera-ny?tab=sponsoring

Discussion