12
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

LispAdvent Calendar 2020

Day 23

Common Lisp で Discord Bot (Lispcord)

Last updated at Posted at 2020-12-27

 Discord の Bot を Common Lisp で作れないかということで、 Lispcord という Common Lisp で Discord Bot の作れるライブラリがあります。しかし、あまりまとまった情報がなかったのでまとめてみました。
 間違っているところがあれば教えていただければ幸いです。

導入

 Quick Lispを使って

(ql:quickload :lispcord)

Bot の作成等

 Bot 自体の作成方法はまとまった情報がすでにあるので、そちらを参照していただくことにして、 Lispcord での必要な作業についてまとめます。

;とりあえずパッケージ

(defpackage :discord-bot
  (:use :cl :lispcord))
(in-package :discord-bot)

;Bot の定義 (TOKEN はダミーです、実際のものを入れてください)
(defbot *bot* "70X3И0§£']['ë|)4+73.05!3I2|<4")

;Bot の接続
(connect *bot*)

;Bot の切断
(disconnect *bot*)

返信等

 とりあえず、 $link って打つと Quick Lisp のリンクを返す Bot のコードです。 ()

(ql:quickload :lispcord)

(defpackage :discord-bot
  (:use :cl :lispcord))
(in-package :discord-bot)

;Bot の定義 (TOKEN はダミーです、実際のものを入れてください)
(defbot *bot* "70X3И0§£']['ë|)4+73.05!3I2|<4")
(connect *bot*)


(add-event-handler :on-message-create
                   (lambda (msg)
                     (when (equal (lc:content msg) "$link")
                           (reply msg "https://www.quicklisp.org/")))

 (add-event-handler :on-message-create 関数)を実行すると、 Bot が入っているサーバーでメッセージが送信されるたびにmsgを引数にその関数が呼び出されるようになります。(lc:contents msg)とすることでメッセージの本文が帰ってくるのでそれが"$link"だったら返信します。( addevent-handler で複数回関数を登録したら、一番最後に登録した関数だけ実行され、前に登録された関数は実行されないことに注意 )
 (reply msg contents) とすることでメッセージが送られたチャンネルに contents を送信できます。
 よく使う関数について簡単に見ていきます。

メッセージの送信

 メッセージの送信に使う関数についてです。

lc:make-message

 文字列だけでなく、 Embed を埋め込んだりしたメッセージを作成します。 (lc:make-message <本文> :embed <embed> :tts <tts> :file <file>) のように使います。( embed, tts, file は必要に応じてつける ( つまり &key ) です。)

(reply <msg> (lc:make-message <本文> :embed <embed>))

といった感じで使うことができます。

create

 (create <content> (from-id <id> :channel)) とすることで、<content><id> のチャンネルに送信できます。(lc:channel-id <msg>) とすることでメッセージが送信されたチャンネルを調べることができ、 reply はそれを使って実装されています。

reply

 (reply <msg> <content>) メッセージが送信されたチャンネルに <content> を送信します。

メッセージからの取得

 メッセージからチャンネルなどの取得について。

lc:content

 (lc:content msg) とすることで、メッセージの本文を取得できます。

lc:channel-id

 (lc:channel-id) とすることで、メッセージが送信されたチャンネルの id を取得できます

Embed 関係

 便利な Embed の送信方法についてです。細かいところは説明しないので、下記の記事などを読んどくと良いかもしれません。

lc:make-embed

(lc:make-embed :title <title> :type <type> :description <description> :url <url> :timestamp <timestamp> :color <color> :footer <footer> :image <image> :thumbnail <thumnail> :video <video> :provider <provider> :author <author> :fields <fields>)

のようになっています。

Embed の送信の例

 関数じゃないですが、まあ例です。$quicklisp を送ると Quick Lisp のリンクが入った Embed を送信します。

(ql:quickload :lispcord)

(defpackage :discord-bot
  (:use :cl :lispcord))
(in-package :discord-bot)

;Bot の定義 (TOKEN はダミーです、実際のものを入れてください)
(defbot *bot* "70X3И0§£']['ë|)4+73.05!3I2|<4")
(connect *bot*)


;Embed の作成
(defparameter *embed-quicklisp* (lc:make-message ""
                                                 :embed (lispcord.classes:make-embed :title "Quick Lisp"
                                                                                     :description "[Quick Lisp](https://www.quicklisp.org/)")))

;$quicklisp が送られたら Embed を送信するようにする。
(add-event-handler :on-message-create
                   (lambda (msg) 
                     (when (equal (lc:content msg) "$quicklisp")
                       (reply msg *embed-quicklisp*))))

 実際に使ってみると下のような感じになります。
image.png

本格的な Bot の作成

 コマンド 引数等 を送信すると、コマンドを Hash Table に保存して実行できるようにしてみました。

(ql:quickload :lispcord)
(ql:quickload :cl-ppcre)

(defpackage :discord-bot
  (:use :cl :lispcord))
(in-package :discord-bot)

;Bot の定義 (TOKEN はダミーです、実際のものを入れてください)
(defbot *bot* "70X3И0§£']['ë|)4+73.05!3I2|<4")
(connect *bot*)

;コマンドの Hash Table の定義
(defparameter *commands* (make-hash-table :test #'equal))

(add-event-handler :on-message-create
                   (lambda (msg)
                     ;cl-ppcre:split で分割する
                     (let ((str (cl-ppcre:split " " (lc:content msg))))
                       ;コマンドが Hash Table に登録されていれば実行する。
                       (when (gethash (first str) *commands*)
                         (funcall (gethash (first str) *commands*) msg str)))))

;Embed の定義 (先程のものと同じ)
(defparameter *embed-quicklisp* (lc:make-message ""
                                                 :embed (lispcord.classes:make-embed :title "Quick Lisp"
                                                                                     :description "[Quick Lisp](https://www.quicklisp.org/)")))

;コマンド "$quicklisp" を Hash Table に登録
(setf (gethash "$quicklisp" *commands*)
      #'(lambda (msg str)
          (reply msg *embed-quicklisp*))) 

;コマンド "$quicklisp" を Hash Table に登録
(setf (gethash "$link" *commands*) 
      #'(lambda (msg str) 
          (reply msg "https://www.quicklisp.org/")))

おわりに

 まだ Lispcord の機能のほんの一部しかまとめてないので、少しずつ内容を増やしていく予定です。また、間違い等があったら、コメントでの指摘や編集リクエストをよろしくおねがいします。ここまで読んでいただきありがとうございます。

12
4
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
12
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?