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