Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
4
Help us understand the problem. What are the problem?

posted at

updated at

Organization

Common Lisp で Discord Bot (Lispcord)

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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
4
Help us understand the problem. What are the problem?